home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 253 / Issue 253 - March 2009 - DPCS0309DVD.ISO / Toolkit / Internet / WinHTTrack / httrack-3.43.exe / {app} / src / htslib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1980-01-01  |  158.8 KB  |  5,690 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: Subroutines                                            */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. /* Internal engine bytecode */
  38. #define HTS_INTERNAL_BYTECODE
  39.  
  40. // Fichier librairie .c
  41.  
  42. #include "htscore.h"
  43.  
  44. #ifdef _WIN32_WCE
  45. #ifndef HTS_CECOMPAT
  46. #pragma comment(lib, "celib.lib") //link with celib
  47. #endif
  48. #endif
  49.  
  50. /* specific definitions */
  51. #include "htsbase.h"
  52. #include "htsnet.h"
  53. #include "htsbauth.h"
  54. #include "htsthread.h"
  55. #include "htsback.h"
  56. #include "htswrap.h"
  57. #include "htsmd5.h"
  58. #include "htsmodules.h"
  59.  
  60. #ifdef _WIN32
  61. #ifndef  _WIN32_WCE
  62. #include <direct.h>
  63. #endif
  64. #else
  65. #ifdef HAVE_SYS_TYPES_H
  66. #include <sys/types.h>
  67. #endif
  68. #ifdef HAVE_SYS_STAT_H
  69. #include <sys/stat.h>
  70. #endif
  71. #ifdef HAVE_UNISTD_H
  72. #include <unistd.h>
  73. #endif
  74. #endif  /* _WIN32 */
  75.  
  76. #include <string.h>
  77. #include <time.h>
  78.  
  79. #ifndef  _WIN32_WCE
  80. #include <sys/timeb.h>
  81. #include <fcntl.h>
  82. #else
  83. #ifndef HTS_CECOMPAT
  84. #include <sys/timeb.h>
  85. #endif
  86. #endif  /* _WIN32_WCE */
  87.  
  88. // pour utimbuf
  89. #ifdef _WIN32
  90. #ifndef _WIN32_WCE
  91. #include <sys/utime.h>
  92. #else
  93. #ifndef HTS_CECOMPAT
  94. #include <sys/utime.h>
  95. #endif
  96. #endif
  97. #else
  98. #include <utime.h>
  99. #endif  /* _WIN32 */
  100.  
  101. #ifndef _WIN32_WCE
  102. #include <sys/stat.h>
  103. #endif
  104. /* END specific definitions */
  105.  
  106.  
  107. // Debugging
  108. #if _HTS_WIDE
  109. FILE* DEBUG_fp=NULL;
  110. #endif
  111.  
  112. /* variables globales */
  113. int _DEBUG_HEAD;
  114. FILE* ioinfo;
  115.  
  116. #if HTS_USEOPENSSL
  117.  SSL_CTX *openssl_ctx = NULL;
  118. #endif
  119. int IPV6_resolver = 0;
  120.  
  121. /* dΘtection complΘmentaire */
  122. const char* hts_detect[] = {
  123.   "archive",
  124.   "background",
  125.   "data",         // OBJECT
  126.   "dynsrc",
  127.   "lowsrc",
  128.   "profile",      // element META
  129.   "src",
  130.   "swurl",
  131.   "url",
  132.   "usemap",
  133.   "longdesc",     // accessibility
  134.   "xlink:href",   // xml/svg tag
  135.   ""
  136. };
  137.  
  138. /* dΘtecter dΘbut */
  139. const char* hts_detectbeg[] = {
  140.   "hotspot",      /* hotspot1=..,hotspot2=.. */
  141.   ""
  142. };
  143.  
  144. /* ne pas dΘtcter de liens dedans */
  145. const char* hts_nodetect[] = {
  146.   "accept-charset",
  147.   "accesskey",
  148.   "action",
  149.   "align",
  150.   "alt",
  151.   "axes",
  152.   "axis",
  153.   "char",
  154.   "charset",
  155.   "cite",
  156.   "class",
  157.   "classid",
  158.   "code",
  159.   "color",
  160.   "datetime",
  161.   "dir",
  162.   "enctype",
  163.   "face",
  164.   "height",
  165.   "id",
  166.   "lang",
  167.   "language",
  168.   "media",
  169.   "method",
  170.   "name",
  171.   "prompt",
  172.   "scheme",
  173.   "size",
  174.   "style",
  175.   "target",
  176.   "title",
  177.   "type",
  178.   "valign",
  179.   "version",
  180.   "width",
  181.   ""
  182. };
  183.  
  184.  
  185. /* dΘtection de mini-code javascript */
  186. /* ALSO USED: detection based on the name: onXXX="<tag>" where XXX starts with upper case letter */
  187. const char* hts_detect_js[] = {
  188.   "onAbort",
  189.   "onBlur",
  190.   "onChange",
  191.   "onClick",
  192.   "onDblClick",
  193.   "onDragDrop",
  194.   "onError",
  195.   "onFocus",
  196.   "onKeyDown",
  197.   "onKeyPress",
  198.   "onKeyUp",
  199.   "onLoad",
  200.   "onMouseDown",
  201.   "onMouseMove",
  202.   "onMouseOut",
  203.   "onMouseOver",
  204.   "onMouseUp",
  205.   "onMove",
  206.   "onReset",
  207.   "onResize",
  208.   "onSelect",
  209.   "onSubmit",
  210.   "onUnload",
  211.   "style",          /* hack for CSS code data */
  212.   ""
  213. };
  214.  
  215. const char* hts_main_mime[] = {
  216.   "application",
  217.   "audio",
  218.   "image",
  219.   "message",
  220.   "multipart",
  221.   "text",
  222.   "video",
  223.   ""
  224. };
  225.  
  226. /* dΘtection "...URL=<url>" */
  227. const char* hts_detectURL[] = {
  228.   "content",
  229.   ""
  230. };
  231.  
  232. /* tags o∙ l'URL doit Ωtre rΘΘcrite mais non capturΘe */
  233. const char* hts_detectandleave[] = {
  234.   "action",
  235.   ""
  236. };
  237.  
  238. /* ne pas renommer les types renvoyΘs (souvent types inconnus) */
  239. const char* hts_mime_keep[] = {
  240.   "application/octet-stream",
  241.   "text/plain",
  242.   ""
  243. };
  244.  
  245. /* bogus servers returns these mime types when the extension is seen within the filename */
  246. const char* hts_mime_bogus_multiple[] = {
  247.   "application/x-wais-source",  /* src (src.rpm) */
  248.   ""
  249. };
  250.  
  251. /* pas de type mime connu, mais extension connue */
  252. const char* hts_ext_dynamic[] = {
  253.   "php3",
  254.   "php",
  255.   "php4",
  256.   "php2",
  257.   "cgi",
  258.   "asp",
  259.   "jsp",
  260.   "pl",
  261.   /*"exe",*/
  262.   "cfm",
  263.   "nsf", /* lotus */
  264.   ""
  265. };
  266.  
  267. /* types MIME 
  268.    note: application/octet-stream should not be used here
  269. */
  270. const char* hts_mime[][2] = {
  271.   {"application/acad","dwg"},
  272.   {"application/arj","arj"},
  273.   {"application/clariscad","ccad"},
  274.   {"application/drafting","drw"},
  275.   {"application/dxf","dxf"},
  276.   {"application/excel","xls"},
  277.   {"application/i-deas","unv"},
  278.   {"application/iges","isg"},
  279.   {"application/iges","iges"},
  280.   {"application/mac-binhex40","hqx"},
  281.   {"application/mac-compactpro","cpt"},
  282.   {"application/msword","doc"},
  283.   {"application/msword","w6w"},
  284.   {"application/msword","word"},
  285.   {"application/mswrite","wri"},
  286.   /*{"application/octet-stream","dms"},*/
  287.   /*{"application/octet-stream","lzh"},*/
  288.   /*{"application/octet-stream","lha"},*/
  289.   /*{"application/octet-stream","bin"},*/
  290.   {"application/oda","oda"},
  291.   {"application/pdf","pdf"},
  292.   {"application/postscript","ps"},
  293.   {"application/postscript","ai"},
  294.   {"application/postscript","eps"},
  295.   {"application/powerpoint","ppt"},
  296.   {"application/pro_eng","prt"},
  297.   {"application/pro_eng","part"},
  298.   {"application/rtf","rtf"},
  299.   {"application/set","set"},
  300.   {"application/sla","stl"},
  301.   {"application/smil","smi"},
  302.   {"application/smil","smil"},
  303.   {"application/smil","sml"},
  304.   {"application/solids","sol"},
  305.   {"application/STEP","stp"},
  306.   {"application/STEP","step"},
  307.   {"application/vda","vda"},
  308.   {"application/x-authorware-map","aam"},     
  309.   {"application/x-authorware-seg","aas"},
  310.   {"application/x-authorware-bin","aab"},
  311.   {"application/x-bzip2","bz2"},
  312.   {"application/x-cocoa","cco"},
  313.   {"application/x-csh","csh"},
  314.   {"application/x-director","dir"},
  315.   {"application/x-director","dcr"},
  316.   {"application/x-director","dxr"},
  317.   {"application/x-mif","mif"},
  318.   {"application/x-dvi","dvi"},
  319.   {"application/x-gzip","gz"},
  320.   {"application/x-gzip","gzip"},
  321.   {"application/x-hdf","hdf"},
  322.   {"application/x-javascript","js"},
  323.   {"application/x-koan","skp"},
  324.   {"application/x-koan","skd"},
  325.   {"application/x-koan","skt"},
  326.   {"application/x-koan","skm"},
  327.   {"application/x-latex","latex"},
  328.   {"application/x-netcdf","nc"},
  329.   {"application/x-netcdf","cdf"},
  330.   /* {"application/x-sh","sh"}, */
  331.   /* {"application/x-csh","csh"}, */
  332.   /* {"application/x-ksh","ksh"}, */
  333.   {"application/x-shar","shar"},
  334.   {"application/x-stuffit","sit"},
  335.   {"application/x-tcl","tcl"},
  336.   {"application/x-tex","tex"},
  337.   {"application/x-texinfo","texinfo"},
  338.   {"application/x-texinfo","texi"},
  339.   {"application/x-troff","t"},
  340.   {"application/x-troff","tr"},
  341.   {"application/x-troff","roff"},
  342.   {"application/x-troff-man","man"},
  343.   {"application/x-troff-me","ms"},
  344.   {"application/x-wais-source","src"},
  345.   {"application/zip","zip"},
  346.   {"application/x-zip-compressed","zip"},
  347.   {"application/x-bcpio","bcpio"},
  348.   {"application/x-cdlink","vcd"},
  349.   {"application/x-cpio","cpio"},
  350.   {"application/x-gtar","tgz"},
  351.   {"application/x-gtar","gtar"},
  352.   {"application/x-shar","shar"},
  353.   {"application/x-shockwave-flash","swf"},
  354.   {"application/x-sv4cpio","sv4cpio"},
  355.   {"application/x-sv4crc","sv4crc"},
  356.   {"application/x-tar","tar"},
  357.   {"application/x-ustar","ustar"},
  358.   {"application/x-winhelp","hlp"},
  359.   {"application/xml","xml"},  
  360.   {"audio/midi","mid"},
  361.   {"audio/midi","midi"},
  362.   {"audio/midi","kar"},
  363.   {"audio/mpeg","mp3"},
  364.   {"audio/mpeg","mpga"},
  365.   {"audio/mpeg","mp2"},
  366.   {"audio/basic","au"},
  367.   {"audio/basic","snd"},
  368.   {"audio/x-aiff","aif"},
  369.   {"audio/x-aiff","aiff"},
  370.   {"audio/x-aiff","aifc"},
  371.   {"audio/x-pn-realaudio","rm"},
  372.   {"audio/x-pn-realaudio","ram"},
  373.   {"audio/x-pn-realaudio","ra"},
  374.   {"audio/x-pn-realaudio-plugin","rpm"},
  375.   {"audio/x-wav","wav"},
  376.   {"chemical/x-pdb","pdb"},
  377.   {"chemical/x-pdb","xyz"},
  378.   {"drawing/x-dwf","dwf"},
  379.   {"image/gif","gif"},
  380.   {"image/ief","ief"},
  381.   {"image/jpeg","jpg"},
  382.   {"image/jpeg","jpe"},
  383.   {"image/jpeg","jpeg"},
  384.   {"image/pict","pict"},
  385.   {"image/png","png"},
  386.   {"image/tiff","tiff"},
  387.   {"image/tiff","tif"},
  388.   {"image/svg+xml","svg"},
  389.   {"image/svg-xml","svg"},
  390.   {"image/x-cmu-raster","ras"},
  391.   {"image/x-freehand","fh4"},
  392.   {"image/x-freehand","fh7"},
  393.   {"image/x-freehand","fh5"},  
  394.   {"image/x-freehand","fhc"},
  395.   {"image/x-freehand","fh"},   
  396.   {"image/x-portable-anymap","pnm"},
  397.   {"image/x-portable-bitmap","pgm"},
  398.   {"image/x-portable-pixmap","ppm"},
  399.   {"image/x-rgb","rgb"},
  400.   {"image/x-xbitmap","xbm"},
  401.   {"image/x-xpixmap","xpm"},
  402.   {"image/x-xwindowdump","xwd"},
  403.   {"model/mesh","msh"},  
  404.   {"model/mesh","mesh"},  
  405.   {"model/mesh","silo"},  
  406.   {"multipart/x-zip","zip"},
  407.   {"multipart/x-gzip","gzip"},
  408.   {"text/css","css"},
  409.   {"text/html","html"},
  410.   {"text/html","htm"},
  411.   {"text/plain","txt"},
  412.   {"text/plain","g"},
  413.   {"text/plain","h"},
  414.   {"text/plain","c"},
  415.   {"text/plain","cc"},
  416.   {"text/plain","hh"},
  417.   {"text/plain","m"},
  418.   {"text/plain","f90"},
  419.   {"text/richtext","rtx"},
  420.   {"text/tab-separated-values","tsv"},
  421.   {"text/x-setext","etx"},
  422.   {"text/x-sgml","sgml"},
  423.   {"text/x-sgml","sgm"},
  424.   {"text/xml","xml"},  
  425.   {"text/xml","dtd"},  
  426.   {"video/mpeg","mpeg"},
  427.   {"video/mpeg","mpg"},
  428.   {"video/mpeg","mpe"},
  429.   {"video/quicktime","qt"},
  430.   {"video/quicktime","mov"},
  431.   {"video/x-msvideo","avi"},
  432.   {"video/x-sgi-movie","movie"},
  433.   {"x-conference/x-cooltalk","ice"},
  434.   /*{"application/x-httpd-cgi","cgi"},*/
  435.   {"x-world/x-vrml","wrl"},
  436.  
  437.   /* More from w3schools.com */
  438.   { "application/envoy", "evy" },
  439.   { "application/fractals", "fif" },
  440.   { "application/futuresplash", "spl" },
  441.   { "application/hta", "hta" },
  442.   { "application/internet-property-stream", "acx" },
  443.   { "application/msword", "dot" },
  444.   { "application/olescript", "axs" },
  445.   { "application/pics-rules", "prf" },
  446.   { "application/pkcs10", "p10" },
  447.   { "application/pkix-crl", "crl" },
  448.   { "application/set-payment-initiation", "setpay" },
  449.   { "application/set-registration-initiation", "setreg" },
  450.   { "application/vnd.ms-excel", "xls" },
  451.   { "application/vnd.ms-excel", "xla" },
  452.   { "application/vnd.ms-excel", "xlc" },
  453.   { "application/vnd.ms-excel", "xlm" },
  454.   { "application/vnd.ms-excel", "xlt" },
  455.   { "application/vnd.ms-excel", "xlw" },
  456.   { "application/vnd.ms-pkicertstore", "sst" },
  457.   { "application/vnd.ms-pkiseccat", "cat" },
  458.   { "application/vnd.ms-powerpoint", "ppt" },
  459.   { "application/vnd.ms-powerpoint", "pot" },
  460.   { "application/vnd.ms-powerpoint", "pps" },
  461.   { "application/vnd.ms-project", "mpp" },
  462.   { "application/vnd.ms-works", "wcm" },
  463.   { "application/vnd.ms-works", "wdb" },
  464.   { "application/vnd.ms-works", "wks" },
  465.   { "application/vnd.ms-works", "wps" },
  466.   { "application/x-compress", "z" },
  467.   { "application/x-compressed", "tgz" },
  468.   { "application/x-internet-signup", "ins" },
  469.   { "application/x-internet-signup", "isp" },
  470.   { "application/x-iphone", "iii" },
  471.   { "application/x-javascript", "js" },
  472.   { "application/x-msaccess", "mdb" },
  473.   { "application/x-mscardfile", "crd" },
  474.   { "application/x-msclip", "clp" },
  475.   { "application/x-msmediaview", "m13" },
  476.   { "application/x-msmediaview", "m14" },
  477.   { "application/x-msmediaview", "mvb" },
  478.   { "application/x-msmetafile", "wmf" },
  479.   { "application/x-msmoney", "mny" },
  480.   { "application/x-mspublisher", "pub" },
  481.   { "application/x-msschedule", "scd" },
  482.   { "application/x-msterminal", "trm" },
  483.   { "application/x-perfmon", "pma" },
  484.   { "application/x-perfmon", "pmc" },
  485.   { "application/x-perfmon", "pml" },
  486.   { "application/x-perfmon", "pmr" },
  487.   { "application/x-perfmon", "pmw" },
  488.   { "application/x-pkcs12", "p12" },
  489.   { "application/x-pkcs12", "pfx" },
  490.   { "application/x-pkcs7-certificates", "p7b" },
  491.   { "application/x-pkcs7-certificates", "spc" },
  492.   { "application/x-pkcs7-certreqresp", "p7r" },
  493.   { "application/x-pkcs7-mime", "p7c" },
  494.   { "application/x-pkcs7-mime", "p7m" },
  495.   { "application/x-pkcs7-signature", "p7s" },
  496.   { "application/x-troff-me", "me" },
  497.   { "application/x-x509-ca-cert", "cer" },
  498.   { "application/x-x509-ca-cert", "crt" },
  499.   { "application/x-x509-ca-cert", "der" },
  500.   { "application/ynd.ms-pkipko", "pko" },
  501.   { "audio/mid", "mid" },
  502.   { "audio/mid", "rmi" },
  503.   { "audio/mpeg", "mp3" },
  504.   { "audio/x-mpegurl", "m3u" },
  505.   { "image/bmp", "bmp" },
  506.   { "image/cis-cod", "cod" },
  507.   { "image/pipeg", "jfif" },
  508.   { "image/x-cmx", "cmx" },
  509.   { "image/x-icon", "ico" },
  510.   { "image/x-portable-bitmap", "pbm" },
  511.   { "message/rfc822", "mht" },
  512.   { "message/rfc822", "mhtml" },
  513.   { "message/rfc822", "nws" },
  514.   { "text/css", "css" },
  515.   { "text/h323", "323" },
  516.   { "text/html", "stm" },
  517.   { "text/iuls", "uls" },
  518.   { "text/plain", "bas" },
  519.   { "text/scriptlet", "sct" },
  520.   { "text/webviewhtml", "htt" },
  521.   { "text/x-component", "htc" },
  522.   { "text/x-vcard", "vcf" },
  523.   { "video/mpeg", "mp2" },
  524.   { "video/mpeg", "mpa" },
  525.   { "video/mpeg", "mpv2" },
  526.   { "video/x-la-asf", "lsf" },
  527.   { "video/x-la-asf", "lsx" },
  528.   { "video/x-ms-asf", "asf" },
  529.   { "video/x-ms-asf", "asr" },
  530.   { "video/x-ms-asf", "asx" },
  531.   { "video/x-ms-wmv", "wmv" },
  532.   { "x-world/x-vrml", "flr" },
  533.   { "x-world/x-vrml", "vrml" },
  534.   { "x-world/x-vrml", "wrz" },
  535.   { "x-world/x-vrml", "xaf" },
  536.   { "x-world/x-vrml", "xof" },
  537.  
  538.   /* Various */
  539.   { "application/ogg", "ogg" },
  540.  
  541.   {"application/x-java-vm","class"},
  542.   
  543.   {"",""}};
  544.  
  545.  
  546. // Reserved (RFC2396)
  547. #define CIS(c,ch) ( ((unsigned char)(c)) == (ch) )
  548. #define CHAR_RESERVED(c)  ( CIS(c,';') \
  549.                          || CIS(c,'/') \
  550.                          || CIS(c,'?') \
  551.                          || CIS(c,':') \
  552.                          || CIS(c,'@') \
  553.                          || CIS(c,'&') \
  554.                          || CIS(c,'=') \
  555.                          || CIS(c,'+') \
  556.                          || CIS(c,'$') \
  557.                          || CIS(c,',') )
  558. //#define CHAR_RESERVED(c)  ( strchr(";/?:@&=+$,",(unsigned char)(c)) != 0 )
  559. // Delimiters (RFC2396)
  560. #define CHAR_DELIM(c)     ( CIS(c,'<') \
  561.                          || CIS(c,'>') \
  562.                          || CIS(c,'#') \
  563.                          || CIS(c,'%') \
  564.                          || CIS(c,'\"') )
  565. //#define CHAR_DELIM(c)     ( strchr("<>#%\"",(unsigned char)(c)) != 0 )
  566. // Unwise (RFC2396)
  567. #define CHAR_UNWISE(c)    ( CIS(c,'{') \
  568.                          || CIS(c,'}') \
  569.                          || CIS(c,'|') \
  570.                          || CIS(c,'\\') \
  571.                          || CIS(c,'^') \
  572.                          || CIS(c,'[') \
  573.                          || CIS(c,']') \
  574.                          || CIS(c,'`') )
  575. //#define CHAR_UNWISE(c)    ( strchr("{}|\\^[]`",(unsigned char)(c)) != 0 )
  576. // Special (escape chars) (RFC2396 + >127 )
  577. #define CHAR_LOW(c)       ( ((unsigned char)(c) <= 31) )
  578. #define CHAR_HIG(c)       ( ((unsigned char)(c) >= 127) )
  579. #define CHAR_SPECIAL(c)   ( CHAR_LOW(c) || CHAR_HIG(c) )
  580. // We try to avoid them and encode them instead
  581. #define CHAR_XXAVOID(c)   ( CIS(c,' ') \
  582.                          || CIS(c,'*') \
  583.                          || CIS(c,'\'') \
  584.                          || CIS(c,'\"') \
  585.                          || CIS(c,'&') \
  586.                          || CIS(c,'!') )
  587. //#define CHAR_XXAVOID(c)   ( strchr(" *'\"!",(unsigned char)(c)) != 0 )
  588. #define CHAR_MARK(c)      ( CIS(c,'-') \
  589.                          || CIS(c,'_') \
  590.                          || CIS(c,'.') \
  591.                          || CIS(c,'!') \
  592.                          || CIS(c,'~') \
  593.                          || CIS(c,'*') \
  594.                          || CIS(c,'\'') \
  595.                          || CIS(c,'(') \
  596.                          || CIS(c,')') )
  597. //#define CHAR_MARK(c)      ( strchr("-_.!~*'()",(unsigned char)(c)) != 0 )
  598.  
  599.  
  600.  
  601. // conversion Θventuelle / vers antislash
  602. #ifdef _WIN32
  603. char* antislash(char *catbuff, const char* s) {
  604.   char* a;
  605.   strcpybuff(catbuff,s);
  606.   while(a=strchr(catbuff,'/')) *a='\\';
  607.   return catbuff;
  608. }
  609. #endif
  610.  
  611. #ifdef _WIN32_WCE
  612. char cwd[MAX_PATH+1] = "";
  613. #endif
  614.  
  615. // RΘcupΘration d'un fichier http sur le net.
  616. // Renvoie une adresse sur le bloc de mΘmoire, ou bien
  617. // NULL si un retour.msgeur (buffer retour.msg) est survenue. 
  618. //
  619. // Une adresse de structure htsmsg peut Ωtre transmise pour
  620. // suivre l'Θvolution du chargement si le process a ΘtΘ lancΘ 
  621. // en background
  622.  
  623. htsblk httpget(httrackp *opt,char* url) {
  624.   char BIGSTK adr[HTS_URLMAXSIZE*2];   // adresse
  625.   char BIGSTK fil[HTS_URLMAXSIZE*2];   // chemin
  626.   
  627.   // sΘparer URL en adresse+chemin
  628.   if (ident_url_absolute(url,adr,fil)==-1) {
  629.     htsblk retour;
  630.     memset(&retour, 0, sizeof(htsblk));    // effacer
  631.     // retour prΘdΘfini: erreur
  632.     retour.adr=NULL;
  633.     retour.size=0;
  634.     retour.msg[0]='\0';
  635.     retour.statuscode=STATUSCODE_INVALID;    
  636.     strcpybuff(retour.msg,"Error invalid URL");
  637.     return retour;
  638.   }
  639.   
  640.   return xhttpget(opt,adr,fil);
  641. }
  642.  
  643. // ouvre une liaison http, envoie une requΦte GET et rΘceptionne le header
  644. // retour: socket
  645. int http_fopen(httrackp *opt,char* adr,char* fil,htsblk* retour) {
  646.   //                / GET, traiter en-tΩte
  647.   return http_xfopen(opt,0,1,1,NULL,adr,fil,retour);
  648. }
  649.  
  650. // ouverture d'une liaison http, envoi d'une requΦte
  651. // mode: 0 GET  1 HEAD  [2 POST]
  652. // treat: traiter header?
  653. // waitconnect: attendre le connect()
  654. // note: dans retour, on met les params du proxy
  655. int http_xfopen(httrackp *opt,int mode,int treat,int waitconnect,char* xsend,char* adr,char* fil,htsblk* retour) {
  656.   //htsblk retour;
  657.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  658.   T_SOC soc=INVALID_SOCKET;
  659.   //char *p,*q;
  660.   
  661.   // retour prΘdΘfini: erreur
  662.   if (retour) {
  663.     retour->adr=NULL;
  664.     retour->size=0;
  665.     retour->msg[0]='\0';
  666.     retour->statuscode=STATUSCODE_NON_FATAL;          // a priori erreur non fatale
  667.   }
  668.  
  669. #if HDEBUG
  670.   printf("adr=%s\nfichier=%s\n",adr,fil);
  671. #endif
  672.   
  673.   // ouvrir liaison
  674. #if HDEBUG
  675.   printf("CrΘation d'une socket sur %s\n",adr);
  676. #endif
  677.  
  678. #if CNXDEBUG
  679.   printf("..newhttp\n");
  680. #endif
  681.  
  682.   /* connexion */
  683.   if (retour) {
  684.     if ( (!(retour->req.proxy.active)) 
  685.       ||
  686.       (
  687.         (strcmp(adr,"file://")==0) 
  688.         ||
  689.         (strncmp(adr,"https://", 8)==0) 
  690.       )
  691.       ) {    /* pas de proxy, ou non utilisable ici */
  692.       soc=newhttp(opt,adr,retour,-1,waitconnect);
  693.     } else {
  694.       soc=newhttp(opt, retour->req.proxy.name, retour,retour->req.proxy.port, waitconnect);  // ouvrir sur le proxy α la place
  695.     }
  696.   } else {
  697.     soc=newhttp(opt,adr,NULL,-1,waitconnect);    
  698.   }
  699.  
  700.   // copier index socket retour
  701.   if (retour) retour->soc=soc;
  702.  
  703.   /* Check for errors */
  704.   if (soc == INVALID_SOCKET) {
  705.     if (retour) {
  706.       if (retour->msg) {
  707.         if (!strnotempty(retour->msg)) {
  708. #ifdef _WIN32
  709.           int last_errno = WSAGetLastError();
  710.           sprintf(retour->msg,"Connect error: %s", strerror(last_errno));
  711. #else
  712.           int last_errno = errno;
  713.           sprintf(retour->msg,"Connect error: %s", strerror(last_errno));
  714. #endif
  715.         }
  716.       }
  717.     }
  718.   }
  719.  
  720.   // --------------------
  721.   // court-circuit (court circuite aussi le proxy..)
  722.   // LOCAL_SOCKET_ID est une pseudo-socket locale
  723.   if (soc==LOCAL_SOCKET_ID) {
  724.     retour->is_file=1;  // fichier local
  725.     if (mode==0) {    // GET
  726.  
  727.       // Test en cas de file:///C|...
  728.       if (!fexist(fconv(OPT_GET_BUFF(opt), unescape_http(OPT_GET_BUFF(opt),fil))))
  729.         if (fexist(fconv(OPT_GET_BUFF(opt), unescape_http(OPT_GET_BUFF(opt),fil+1)))) {
  730.           char BIGSTK tempo[HTS_URLMAXSIZE*2];
  731.           strcpybuff(tempo,fil+1);
  732.           strcpybuff(fil,tempo);
  733.         }
  734.  
  735.       // Ouvrir
  736.       retour->totalsize=fsize(fconv(OPT_GET_BUFF(opt), unescape_http(OPT_GET_BUFF(opt),fil)));  // taille du fichier
  737.       retour->msg[0]='\0';
  738.       soc=INVALID_SOCKET;
  739.       if (retour->totalsize<0)
  740.         strcpybuff(retour->msg,"Unable to open local file");
  741.       else if (retour->totalsize==0)
  742.         strcpybuff(retour->msg,"File empty");
  743.       else {
  744.         // Note: On passe par un FILE* (plus propre)
  745.         //soc=open(fil,O_RDONLY,0);    // en lecture seule!
  746.         retour->fp=fopen(fconv(OPT_GET_BUFF(opt), unescape_http(OPT_GET_BUFF(opt),fil)),"rb");  // ouvrir
  747.         if (retour->fp==NULL)
  748.           soc=INVALID_SOCKET;
  749.         else
  750.           soc=LOCAL_SOCKET_ID;
  751.       }
  752.       retour->soc=soc;
  753.       if (soc!=INVALID_SOCKET) {
  754.         retour->statuscode=HTTP_OK;   // OK
  755.         strcpybuff(retour->msg,"OK");
  756.         guess_httptype(opt,retour->contenttype,fil);
  757.       } else if (strnotempty(retour->msg)==0)
  758.           strcpybuff(retour->msg,"Unable to open local file");
  759.       return soc;  // renvoyer
  760.     } else {    // HEAD ou POST : interdit sur un local!!!! (c'est idiot!)
  761.       strcpybuff(retour->msg,"Unexpected Head/Post local request");
  762.       soc=INVALID_SOCKET;    // erreur
  763.       retour->soc=soc;
  764.       return soc;
  765.     }
  766.   } 
  767.   // --------------------
  768.  
  769.   if (soc!=INVALID_SOCKET) {    
  770.     char rcvd[1100];
  771.     rcvd[0]='\0';
  772. #if HDEBUG
  773.     printf("Ok, connexion rΘussie, id=%d\n",soc);
  774. #endif
  775.     
  776.     // connectΘ?
  777.     if (waitconnect) {
  778.       http_sendhead(opt,NULL,mode,xsend,adr,fil,NULL,NULL,retour);
  779.     } 
  780.     
  781.     if (soc!=INVALID_SOCKET) {
  782.       
  783. #if HDEBUG
  784.       printf("Attente de la rΘponse:\n");
  785. #endif
  786.       
  787.       // si GET (rΘception d'un fichier), rΘceptionner en-tΩte d'abord,
  788.       // et ensuite le corps
  789.       // si POST on ne rΘceptionne rien du tout, c'est aprΦs que l'on fera
  790.       // une rΘception standard pour rΘcupΘrer l'en tΩte
  791.       if ((treat) && (waitconnect)) {  // traiter (attendre!) en-tΩte        
  792.         // RΘception de la status line et de l'en-tΩte (norme RFC1945)
  793.         
  794.         // status-line α rΘcupΘrer
  795.         finput(soc,rcvd,1024);
  796.         if (strnotempty(rcvd)==0)
  797.           finput(soc,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  798.  
  799.         // traiter status-line
  800.         treatfirstline(retour,rcvd);
  801.  
  802. #if HDEBUG
  803.         printf("Status-Code=%d\n",retour->statuscode);
  804. #endif
  805.         
  806.         // en-tΩte
  807.         
  808.         // header // ** !attention! HTTP/0.9 non supportΘ
  809.         do {
  810.           finput(soc,rcvd,1024);          
  811. #if HDEBUG
  812.           printf(">%s\n",rcvd);      
  813. #endif
  814.           if (strnotempty(rcvd))
  815.             treathead(NULL,NULL,NULL,retour,rcvd);  // traiter
  816.  
  817.         } while(strnotempty(rcvd));
  818.         
  819.         //rcvsize=-1;    // forCER CHARGEMENT INCONNU
  820.         
  821.         //if (retour)
  822.         //  retour->totalsize=rcvsize;
  823.         
  824.       } else { // si GET, on recevra l'en tΩte APRES
  825.         //rcvsize=-1;    // on ne connait pas la taille de l'en-tΩte
  826.         if (retour)
  827.           retour->totalsize=-1;
  828.       }
  829.       
  830.     }
  831.  
  832.   }
  833.     
  834.   return soc;
  835. }
  836.  
  837.  
  838. // envoi d'une requΦte
  839. int http_sendhead(httrackp *opt,t_cookie* cookie,int mode,char* xsend,char* adr,char* fil,char* referer_adr,char* referer_fil,htsblk* retour) {
  840.   char BIGSTK buff[8192];
  841.   //int use_11=0;     // HTTP 1.1 utilisΘ
  842.   int direct_url=0; // ne pas analyser l'url (exemple: ftp://)
  843.   char* search_tag=NULL;
  844.   buff[0]='\0';
  845.  
  846.   // header Date
  847.   //strcatbuff(buff,"Date: ");
  848.   //time_gmt_rfc822(buff);    // obtenir l'heure au format rfc822
  849.   //sendc("\n");
  850.   //strcatbuff(buff,buff);
  851.  
  852.   // possibilitΘ non documentΘe: >post: et >postfile:
  853.   // si prΘsence d'un tag >post: alors executer un POST
  854.   // exemple: http://www.someweb.com/test.cgi?foo>post:posteddata=10&foo=5
  855.   // si prΘsence d'un tag >postfile: alors envoyer en tΩte brut contenu dans le fichier en question
  856.   // exemple: http://www.someweb.com/test.cgi?foo>postfile:post0.txt
  857.   search_tag=strstr(fil,POSTTOK":");
  858.   if (!search_tag) {
  859.     search_tag=strstr(fil,POSTTOK"file:");
  860.     if (search_tag) {     // postfile
  861.       if (mode==0) {      // GET!
  862.         FILE* fp=fopen(unescape_http(OPT_GET_BUFF(opt),search_tag+strlen(POSTTOK)+5),"rb");
  863.         if (fp) {
  864.           char BIGSTK line[1100];
  865.           char BIGSTK protocol[256],url[HTS_URLMAXSIZE*2],method[256];
  866.           linput(fp,line,1000);
  867.           if (sscanf(line,"%s %s %s",method,url,protocol) == 3) {
  868.             // selon que l'on a ou pas un proxy
  869.             if (retour->req.proxy.active)
  870.               sprintf(buff,"%s http://%s%s %s\r\n",method,adr,url,protocol);
  871.             else
  872.               sprintf(buff,"%s %s %s\r\n",method,url,protocol);
  873.             // lire le reste en brut
  874.             fread(buff+strlen(buff),8000-strlen(buff),1,fp);
  875.           }
  876.           fclose(fp);
  877.         }
  878.       }
  879.     }
  880.   }
  881.   // Fin postfile
  882.   
  883.   if (strnotempty(buff)==0) {    // PAS POSTFILE
  884.     // Type de requΦte?
  885.     if ((search_tag) && (mode==0)) {
  886.       strcatbuff(buff,"POST ");
  887.     } else if (mode==0) {    // GET
  888.       strcatbuff(buff,"GET ");
  889.     } else {  // if (mode==1) {
  890.       if (!retour->req.http11)        // forcer HTTP/1.0
  891.         strcatbuff(buff,"GET ");      // certains serveurs (cgi) buggent avec HEAD
  892.       else
  893.         strcatbuff(buff,"HEAD ");
  894.     }
  895.     
  896.     // si on gΦre un proxy, il faut une Absolute URI: on ajoute avant http://www.adr.dom
  897.     if ( retour->req.proxy.active && (strncmp(adr,"https://", 8) != 0) ) {
  898.       if (!link_has_authority(adr)) {  // default http
  899. #if HDEBUG
  900.         printf("Proxy Use: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  901. #endif
  902.         strcatbuff(buff,"http://");
  903.         strcatbuff(buff,jump_identification(adr));
  904.       } else {          // ftp:// en proxy http
  905. #if HDEBUG
  906.         printf("Proxy Use for ftp: for %s%s proxy %d port %d\n",adr,fil,retour->req.proxy.name,retour->req.proxy.port);
  907. #endif
  908.         direct_url=1;             // ne pas analyser user/pass
  909.         strcatbuff(buff,adr);
  910.       }
  911.     } 
  912.     
  913.     // NOM DU FICHIER
  914.     // on slash doit Ωtre prΘsent en dΘbut, sinon attention aux bad request! (400)
  915.     if (*fil!='/') strcatbuff(buff,"/");
  916.     {
  917.       char BIGSTK tempo[HTS_URLMAXSIZE*2];
  918.       tempo[0]='\0';
  919.       if (search_tag)
  920.         strncatbuff(tempo,fil,(int) (search_tag - fil));
  921.       else
  922.         strcpybuff(tempo,fil);
  923.       escape_check_url(tempo);
  924.       strcatbuff(buff,tempo);       // avec Θchappement
  925.     }
  926.     
  927.     // protocole
  928.     if (!retour->req.http11) {     // forcer HTTP/1.0
  929.       //use_11=0;
  930.       strcatbuff(buff," HTTP/1.0\x0d\x0a");
  931.     } else {                   // RequΦte 1.1
  932.       //use_11=1;
  933.       strcatbuff(buff," HTTP/1.1\x0d\x0a");
  934.     }
  935.  
  936.     /* supplemental data */
  937.     if (xsend) strcatbuff(buff,xsend);    // Θventuelles autres lignes
  938.  
  939.     // tester proxy authentication
  940.     if (retour->req.proxy.active) {
  941.       if (link_has_authorization(retour->req.proxy.name)) {  // et hop, authentification proxy!
  942.         const char* a = jump_identification(retour->req.proxy.name);
  943.         const char* astart = jump_protocol(retour->req.proxy.name);
  944.         char autorisation[1100];
  945.         char user_pass[256];        
  946.         autorisation[0]=user_pass[0]='\0';
  947.         //
  948.         strncatbuff(user_pass,astart,(int) (a - astart) - 1);
  949.         strcpybuff(user_pass,unescape_http(OPT_GET_BUFF(opt),user_pass));
  950.         code64((unsigned char*)user_pass,(int)strlen(user_pass),(unsigned char*)autorisation,0);
  951.         strcatbuff(buff,"Proxy-Authorization: Basic ");
  952.         strcatbuff(buff,autorisation);
  953.         strcatbuff(buff,H_CRLF);
  954. #if HDEBUG
  955.         printf("Proxy-Authenticate, %s (code: %s)\n",user_pass,autorisation);
  956. #endif
  957.       }
  958.     }
  959.     
  960.     // Referer?
  961.     if (referer_adr != NULL && referer_fil != NULL 
  962.       && strnotempty(referer_adr) && strnotempty(referer_fil)
  963.       ) {   // non vide
  964.       if (
  965.         (strcmp(referer_adr,"file://") != 0)
  966.         &&
  967.         (  /* no https referer to http urls */
  968.         (strncmp(referer_adr, "https://", 8) != 0)  /* referer is not https */
  969.         ||
  970.         (strncmp(adr, "https://", 8) == 0)          /* or referer AND addresses are https */
  971.         )
  972.         ) {      // PAS file://
  973.         strcatbuff(buff,"Referer: ");
  974.         strcatbuff(buff,"http://");
  975.         strcatbuff(buff,jump_identification(referer_adr));
  976.         strcatbuff(buff,referer_fil);
  977.         strcatbuff(buff,H_CRLF);
  978.       }
  979.     }
  980.     // HTTP field: referer
  981.     else if (retour->req.referer[0] != '\0') {
  982.       strcatbuff(buff,"Referer: ");
  983.       strcatbuff(buff, retour->req.referer);
  984.       strcatbuff(buff, H_CRLF);     
  985.     }
  986.     
  987.     // POST?
  988.     if (mode==0) {      // GET!
  989.       if (search_tag) {
  990.         char clen[256];
  991.         sprintf(clen,"Content-length: %d"H_CRLF,(int)(strlen(unescape_http(OPT_GET_BUFF(opt),search_tag+strlen(POSTTOK)+1))));
  992.         strcatbuff(buff,clen);
  993.       }
  994.     }
  995.     
  996.     // gestion cookies?
  997.     if (cookie) {
  998.             char buffer[8192];
  999.       char* b=cookie->data;
  1000.       int cook=0;
  1001.       int max_cookies=8;
  1002.       size_t max_size=2048;
  1003.       max_size+=strlen(buff);
  1004.       do {
  1005.         b=cookie_find(b,"",jump_identification(adr),fil);       // prochain cookie satisfaisant aux conditions
  1006.         if (b) {
  1007.           max_cookies--;
  1008.           if (!cook) {
  1009.             strcatbuff(buff,"Cookie: ");
  1010.             strcatbuff(buff,"$Version=1; ");
  1011.             cook=1;
  1012.           } else
  1013.             strcatbuff(buff,"; ");
  1014.           strcatbuff(buff,cookie_get(buffer,b,5));
  1015.           strcatbuff(buff,"=");
  1016.           strcatbuff(buff,cookie_get(buffer,b,6));
  1017.           strcatbuff(buff,"; $Path=");
  1018.           strcatbuff(buff,cookie_get(buffer,b,2));
  1019.           b=cookie_nextfield(b);
  1020.         }
  1021.       } while( (b) && (max_cookies>0) && ((int)strlen(buff)<max_size));
  1022.       if (cook) {                           // on a envoyΘ un (ou plusieurs) cookie?
  1023.         strcatbuff(buff,H_CRLF);
  1024. #if DEBUG_COOK
  1025.         printf("Header:\n%s\n",buff);
  1026. #endif
  1027.       }
  1028.     }
  1029.     
  1030.     // gΘrer le keep-alive (garder socket)
  1031.     if (retour->req.http11 && !retour->req.nokeepalive) {
  1032.             strcatbuff(buff,"Connection: Keep-Alive"H_CRLF);
  1033.         } else {
  1034.       strcatbuff(buff,"Connection: close"H_CRLF);
  1035.         }
  1036.     
  1037.     {
  1038.       char* real_adr=jump_identification(adr);
  1039.       //if ((use_11) || (retour->user_agent_send)) {   // Pour le 1.1 on utilise un Host:
  1040.       if (!direct_url) {     // pas ftp:// par exemple
  1041.         //if (!retour->req.proxy.active) {
  1042.         strcatbuff(buff,"Host: "); strcatbuff(buff,real_adr); strcatbuff(buff,H_CRLF);
  1043.         //}
  1044.       }
  1045.       //}
  1046.  
  1047.       // HTTP field: from
  1048.       if (retour->req.from[0] != '\0') {  // HTTP from
  1049.         strcatbuff(buff,"From: ");
  1050.         strcatbuff(buff, retour->req.from);
  1051.         strcatbuff(buff, H_CRLF);
  1052.       }
  1053.  
  1054.       // PrΘsence d'un user-agent?
  1055.       if (retour->req.user_agent_send) {  // ohh un user-agent
  1056.         char s[256];
  1057.         // HyperTextSeeker/"HTSVERSION
  1058.         sprintf(s,"User-Agent: %s"H_CRLF,retour->req.user_agent);
  1059.         strcatbuff(buff,s);
  1060.         
  1061.         // pour les serveurs difficiles
  1062.         strcatbuff(buff,"Accept: "
  1063.                         "image/png, image/jpeg, image/pjpeg, image/x-xbitmap, image/svg+xml"  /* Accepted */
  1064.                         ", "
  1065.                         "image/gif;q=0.9"  /* also accepted but with lower preference */
  1066.                         ", "
  1067.                         "*/*;q=0.1"        /* also accepted but with even lower preference */
  1068.                         H_CRLF);
  1069.         if (strnotempty(retour->req.lang_iso)) {
  1070.           strcatbuff(buff,"Accept-Language: "); strcatbuff(buff,retour->req.lang_iso); strcatbuff(buff,H_CRLF);
  1071.         }
  1072.         strcatbuff(buff,"Accept-Charset: "
  1073.                         "iso-8859-1"       /* we prefer ISO-8859-1 */
  1074.                         ", "
  1075.                         "iso-8859-*;q=0.9" /* or ISO-8859-* */
  1076.                         ", "
  1077.                         "utf-8;q=0.66"     /* UTF8 is also accepted */
  1078.                         ", "
  1079.                         "*;q=0.33"         /* and any other charset */
  1080.                         H_CRLF);   
  1081.         if (retour->req.http11) {
  1082. #if HTS_USEZLIB
  1083.           //strcatbuff(buff,"Accept-Encoding: gzip, deflate, compress, identity"H_CRLF);
  1084.           if (gz_is_available && (!retour->req.range_used) && (!retour->req.nocompression))
  1085.             strcatbuff(buff,"Accept-Encoding: "
  1086.                             "gzip"         /* gzip if the preffered encoding */
  1087.                             ", "
  1088.                             "identity;q=0.9"
  1089.                             H_CRLF);
  1090.           else
  1091.             strcatbuff(buff,"Accept-Encoding: identity"H_CRLF);       /* no compression */
  1092. #else
  1093.           strcatbuff(buff,"Accept-Encoding: identity"H_CRLF);         /* no compression */
  1094. #endif
  1095.         }
  1096.       } else {
  1097.         strcatbuff(buff,"Accept: */*"H_CRLF);         // le minimum
  1098.       }
  1099.  
  1100.       /* Authentification */
  1101.       {
  1102.         char autorisation[1100];
  1103.         char* a;
  1104.         autorisation[0]='\0';
  1105.         if (link_has_authorization(adr)) {  // ohh une authentification!
  1106.           char* a=jump_identification(adr);
  1107.           char* astart=jump_protocol(adr);
  1108.           if (!direct_url) {      // pas ftp:// par exemple
  1109.             char user_pass[256];
  1110.             user_pass[0]='\0';
  1111.             strncatbuff(user_pass,astart,(int) (a - astart) - 1);
  1112.             strcpybuff(user_pass,unescape_http(OPT_GET_BUFF(opt),user_pass));
  1113.             code64((unsigned char*)user_pass,(int)strlen(user_pass),(unsigned char*)autorisation,0);
  1114.             if (strcmp(fil,"/robots.txt"))      /* pas robots.txt */
  1115.               bauth_add(cookie,astart,fil,autorisation);
  1116.           }
  1117.         } else if ( (a=bauth_check(cookie,real_adr,fil)) )
  1118.           strcpybuff(autorisation,a);
  1119.         /* On a une autorisation a donner?  */
  1120.         if (strnotempty(autorisation)) {
  1121.           strcatbuff(buff,"Authorization: Basic ");
  1122.           strcatbuff(buff,autorisation);
  1123.           strcatbuff(buff,H_CRLF);
  1124.         }
  1125.       }
  1126.  
  1127.     }
  1128.     //strcatbuff(buff,"Accept-Language: en\n");
  1129.     //strcatbuff(buff,"Accept-Charset: iso-8859-1,*,utf-8\n");
  1130.     
  1131.     // CRLF de fin d'en tΩte
  1132.     strcatbuff(buff,H_CRLF);
  1133.     
  1134.     // donnΘes complΘmentaires?
  1135.     if (search_tag)
  1136.     if (mode==0)      // GET!
  1137.       strcatbuff(buff,unescape_http(OPT_GET_BUFF(opt),search_tag+strlen(POSTTOK)+1));
  1138.   }
  1139.   
  1140. #if HDEBUG
  1141. #endif
  1142.   if (_DEBUG_HEAD) {
  1143.     if (ioinfo) {
  1144.       fprintf(ioinfo,"[%d] request for %s%s:\r\n",retour->debugid,jump_identification(adr),fil);
  1145.       fprintfio(ioinfo,buff,"<<< ");
  1146.       fprintf(ioinfo,"\r\n");
  1147.       fflush(ioinfo);
  1148.     }
  1149.   }  // Fin test pas postfile
  1150.   //
  1151.  
  1152.   // Callback
  1153.   {
  1154.     int test_head = RUN_CALLBACK6(opt, sendhead, buff, adr, fil, referer_adr, referer_fil, retour);
  1155.     if (test_head!=1) {
  1156.       deletesoc_r(retour);
  1157.       strcpybuff(retour->msg,"Header refused by external wrapper");
  1158.       retour->soc=INVALID_SOCKET;
  1159.     }
  1160.   }
  1161.  
  1162.   // Envoi
  1163.   HTS_STAT.last_request = mtime_local();
  1164.   if (sendc(retour, buff)<0) {  // ERREUR, socket rompue?...
  1165.   //if (sendc(retour->soc,buff) != strlen(buff)) {  // ERREUR, socket rompue?...
  1166.     deletesoc_r(retour);  // fermer tout de mΩme
  1167.     // et tenter de reconnecter
  1168.     
  1169.     strcpybuff(retour->msg, "Write error");
  1170.     retour->soc=INVALID_SOCKET;
  1171.   }
  1172.   
  1173.   // RX'98
  1174.   return 0;
  1175. }
  1176.  
  1177.  
  1178.  
  1179.  
  1180. // traiter 1ere ligne d'en tΩte
  1181. void treatfirstline(htsblk* retour,char* rcvd) {
  1182.   char* a=rcvd;
  1183.   // exemple:
  1184.   // HTTP/1.0 200 OK
  1185.   if (*a) {
  1186.     // note: certains serveurs buggΘs renvoient HTTP/1.0\n200 OK ou " HTTP/1.0 200 OK"
  1187.     while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces au dΘbut
  1188.     if (strfield(a, "HTTP/")) {
  1189.       // sauter HTTP/1.x
  1190.       while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  1191.       if (*a != '\0') {
  1192.         while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  1193.         if ((*a>='0') && (*a<='9')) {
  1194.           sscanf(a,"%d",&(retour->statuscode));
  1195.           // sauter 200
  1196.           while ((*a!=' ') && (*a!='\0') && (*a!=10) && (*a!=13) && (*a!=9)) a++;   
  1197.           while ((*a==' ') || (*a==10) || (*a==13) || (*a==9)) a++;      // Θpurer espaces
  1198.           if ((strlen(a) > 1) && (strlen(a) < 64) )                // message retour
  1199.             strcpybuff(retour->msg,a);
  1200.           else
  1201.             infostatuscode(retour->msg,retour->statuscode);
  1202.           // type MIME par dΘfaut2
  1203.           strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1204.         } else {  // pas de code!
  1205.           retour->statuscode=STATUSCODE_INVALID;
  1206.           strcpybuff(retour->msg,"Unknown response structure");
  1207.         }
  1208.       } else {  // euhh??
  1209.         retour->statuscode=STATUSCODE_INVALID;
  1210.         strcpybuff(retour->msg,"Unknown response structure");
  1211.       }
  1212.     } else {
  1213.             if (*a == '<') {
  1214.         /* This is dirty .. */
  1215.         retour->statuscode=HTTP_OK;
  1216.         retour->keep_alive=0;
  1217.         strcpybuff(retour->msg, "Unknown, assuming junky server");
  1218.         strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1219.             } else if (strnotempty(a)) {
  1220.         retour->statuscode=STATUSCODE_INVALID;
  1221.         strcpybuff(retour->msg,"Unknown (not HTTP/xx) response structure");
  1222.       } else {
  1223.         /* This is dirty .. */
  1224.         retour->statuscode=HTTP_OK;
  1225.         retour->keep_alive=0;
  1226.         strcpybuff(retour->msg, "Unknown, assuming junky server");
  1227.         strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1228.       }
  1229.     }
  1230.   } else {  // vide!
  1231.     /*
  1232.     retour->statuscode=STATUSCODE_INVALID;
  1233.     strcpybuff(retour->msg,"Empty reponse or internal error");
  1234.     */
  1235.     /* This is dirty .. */
  1236.     retour->statuscode=HTTP_OK;
  1237.     strcpybuff(retour->msg, "Unknown, assuming junky server");
  1238.     strcpybuff(retour->contenttype,HTS_HYPERTEXT_DEFAULT_MIME);
  1239.   }
  1240. }
  1241.  
  1242. // traiter ligne par ligne l'en tΩte
  1243. // gestion des cookies
  1244. void treathead(t_cookie* cookie,char* adr,char* fil,htsblk* retour,char* rcvd) {
  1245.   int p;
  1246.   if ((p=strfield(rcvd,"Content-length:"))!=0) {
  1247. #if HDEBUG
  1248.     printf("ok, Content-length: dΘtectΘ\n");
  1249. #endif
  1250.     sscanf(rcvd+p,LLintP,&(retour->totalsize));
  1251.     if (retour->totalsize == 0) {
  1252.       retour->empty = 1;
  1253.     }
  1254.   }
  1255.   else if ((p=strfield(rcvd,"Content-Disposition:"))!=0) {
  1256.     while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1257.     if ((int) strlen(rcvd+p)<250) { // pas trop long?
  1258.       char tmp[256];
  1259.       char *a=NULL,*b=NULL;
  1260.       strcpybuff(tmp,rcvd+p);
  1261.       a=strstr(tmp,"filename=");
  1262.       if (a) {
  1263.         a+=strlen("filename=");
  1264.         while(is_space(*a)) a++;
  1265.         //a=strchr(a,'"');
  1266.         if (a) {
  1267.           char *c=NULL;
  1268.           //a++;      /* jump " */
  1269.           while((c=strchr(a,'/')))    /* skip all / (see RFC2616) */
  1270.             a=c+1;
  1271.           //b=strchr(a+1,'"');
  1272.           b=a+strlen(a)-1;
  1273.           while(is_space(*b)) b--;
  1274.           b++;
  1275.           if (b) {
  1276.             *b='\0';
  1277.             if ((int) strlen(a) < 200) { // pas trop long?
  1278.               strcpybuff(retour->cdispo,a);
  1279.             }
  1280.           }
  1281.         }
  1282.       } 
  1283.     }
  1284.   }
  1285.   else if ((p=strfield(rcvd,"Last-Modified:"))!=0) {
  1286.     while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1287.     if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1288.       //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1289.       strcpybuff(retour->lastmodified,rcvd+p);
  1290.     }
  1291.   }
  1292.   else if ((p=strfield(rcvd,"Date:"))!=0) {
  1293.     if (strnotempty(retour->lastmodified)==0) {          /* pas encore de last-modified */
  1294.       while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1295.       if ((int) strlen(rcvd+p)<64) { // pas trop long?
  1296.         //struct tm* tm_time=convert_time_rfc822(rcvd+p);
  1297.         strcpybuff(retour->lastmodified,rcvd+p);
  1298.       }
  1299.     }
  1300.   }
  1301.   else if ((p=strfield(rcvd,"Etag:"))!=0) {   /* Etag */
  1302.     if (retour) {
  1303.       while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1304.       if ((int) strlen(rcvd+p)<64)  // pas trop long?
  1305.         strcpybuff(retour->etag,rcvd+p);
  1306.       else    // erreur.. ignorer
  1307.         retour->etag[0]='\0';
  1308.     }
  1309.   }
  1310.   // else if ((p=strfield(rcvd,"Transfer-Encoding: chunked"))!=0) {  // chunk!
  1311.   else if ((p=strfield(rcvd,"Transfer-Encoding:"))!=0) {  // chunk!
  1312.     while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1313.     if (strfield(rcvd+p,"chunked")) {
  1314.       retour->is_chunk=1;     // chunked
  1315.       //retour->http11=2;     // chunked
  1316. #if HDEBUG
  1317.       printf("ok, Transfer-Encoding: dΘtectΘ\n");
  1318. #endif
  1319.     }
  1320.   }
  1321.   else if ((p=strfield(rcvd,"Content-type:"))!=0) {
  1322.     if (retour) {
  1323.       char tempo[1100];
  1324.       // Θviter les text/html; charset=foo
  1325.       {
  1326.         char* a=strchr(rcvd+p,';');
  1327.         if (a) {   // extended information
  1328.           *a='\0';
  1329.           a++;
  1330.               while(is_space(*a)) a++;
  1331.           if (strfield(a, "charset")) {
  1332.             a += 7;
  1333.                 while(is_space(*a)) a++;
  1334.             if (*a == '=') {
  1335.               a++;
  1336.                   while(is_space(*a)) a++;
  1337.               if (*a == '\"') a++;
  1338.                   while(is_space(*a)) a++;
  1339.               if (*a) {
  1340.                 char* chs = a;
  1341.                 while(*a && !is_space(*a) && *a != '\"' && *a != ';') a++;
  1342.                 *a = '\0';
  1343.                 if (*chs) {
  1344.                   if (strlen(chs) < sizeof(retour->charset) - 2) {
  1345.                     strcpybuff(retour->charset, chs);
  1346.                   }
  1347.                 }
  1348.               }
  1349.             }
  1350.           }
  1351.         }
  1352.       }
  1353.       sscanf(rcvd+p,"%s",tempo);
  1354.       if (strlen(tempo) < sizeof(retour->contenttype) - 2)    // pas trop long!!
  1355.         strcpybuff(retour->contenttype,tempo);
  1356.       else
  1357.         strcpybuff(retour->contenttype,"application/octet-stream-unknown");    // erreur
  1358.     }
  1359.   }
  1360.   else if ((p=strfield(rcvd,"Content-Range:"))!=0) {
  1361.     char* a=strstr(rcvd+p,"*/");
  1362.     if (a) {
  1363.       if (sscanf(a+2,LLintP,&retour->crange) != 1) {
  1364.         retour->crange=0;
  1365.       }
  1366.     }
  1367.   }
  1368.   else if ((p=strfield(rcvd,"Connection:"))!=0) {
  1369.         char* a = rcvd + p;
  1370.         while(is_space(*a)) a++;
  1371.         if (*a) {
  1372.             if (strfield(a, "Keep-Alive")) {
  1373.         if (!retour->keep_alive) {
  1374.           retour->keep_alive_max = 10;
  1375.           retour->keep_alive_t = 15;
  1376.         }
  1377.         retour->keep_alive = 1;
  1378.       } else {
  1379.                 retour->keep_alive = 0;
  1380.       }
  1381.         }
  1382.     }
  1383.   else if ((p=strfield(rcvd,"Keep-Alive:"))!=0) {
  1384.         char* a = rcvd + p;
  1385.         while(is_space(*a)) a++;
  1386.         if (*a) {
  1387.       char* p;
  1388.       retour->keep_alive = 1;
  1389.       retour->keep_alive_max = 10;
  1390.       retour->keep_alive_t = 15;
  1391.       if ((p=strstr(a, "timeout="))) {
  1392.         p+=strlen("timeout=");
  1393.         sscanf(p, "%d", &retour->keep_alive_t);
  1394.       }
  1395.       if ((p=strstr(a, "max="))) {
  1396.         p+=strlen("max=");
  1397.         sscanf(p, "%d", &retour->keep_alive_max);
  1398.       }
  1399.       if (retour->keep_alive_max <= 1 || retour->keep_alive_t < 3) {
  1400.         retour->keep_alive = 0;
  1401.       }
  1402.     }
  1403.   }
  1404.   else if ((p=strfield(rcvd,"TE:"))!=0) {
  1405.         char* a = rcvd + p;
  1406.         while(is_space(*a)) a++;
  1407.         if (*a) {
  1408.       if (strfield(a, "trailers")) {
  1409.         retour->keep_alive_trailers=1;
  1410.       }
  1411.     }
  1412.   }
  1413.     else if ((p=strfield(rcvd,"Content-Encoding:"))!=0) {
  1414.         if (retour) {
  1415.             char tempo[1100];
  1416.       char* a = rcvd + p;
  1417.       while(is_space(*a)) a++;
  1418.             {
  1419.                 char* a=strchr(rcvd+p,';');
  1420.                 if (a) *a='\0';
  1421.             }
  1422.             sscanf(a,"%s",tempo);
  1423.       if (strlen(tempo)<64)    // pas trop long!!
  1424.         strcpybuff(retour->contentencoding,tempo);
  1425.       else
  1426.         retour->contentencoding[0]='\0';    // erreur
  1427. #if HTS_USEZLIB
  1428.       /* Check known encodings */
  1429.       if (retour->contentencoding[0]) {
  1430.         if (
  1431.           (strfield2(retour->contentencoding, "gzip"))
  1432.           || (strfield2(retour->contentencoding, "x-gzip"))
  1433.           /*
  1434.           || (strfield2(retour->contentencoding, "compress"))
  1435.           || (strfield2(retour->contentencoding, "x-compress"))
  1436.           */
  1437.           || (strfield2(retour->contentencoding, "deflate"))
  1438.           || (strfield2(retour->contentencoding, "x-deflate"))
  1439.           ) {
  1440.         retour->compressed=1;
  1441.         }
  1442.       }
  1443. #endif
  1444.     }
  1445.   }
  1446.   else if ((p=strfield(rcvd,"Location:"))!=0) {
  1447.     if (retour) {
  1448.       if (retour->location) {
  1449.         while(is_realspace(*(rcvd+p))) p++;    // sauter espaces
  1450.         if ((int) strlen(rcvd+p)<HTS_URLMAXSIZE)  // pas trop long?
  1451.           strcpybuff(retour->location,rcvd+p);
  1452.         else    // erreur.. ignorer
  1453.           retour->location[0]='\0';
  1454.       }
  1455.     }
  1456.   }
  1457.   else if ( ((p=strfield(rcvd,"Set-Cookie:"))!=0) && (cookie) ) {    // ohh un cookie
  1458.     char* a = rcvd+p;           // pointeur
  1459.     char domain[256];           // domaine cookie (.netscape.com)
  1460.     char path[256];             // chemin (/)
  1461.     char cook_name[256];        // nom cookie (MYCOOK)
  1462.     char BIGSTK cook_value[8192];      // valeur (ID=toto,S=1234)
  1463. #if DEBUG_COOK
  1464.     printf("set-cookie detected\n");
  1465. #endif
  1466.     while(*a) {
  1467.       char *token_st,*token_end;
  1468.       char *value_st,*value_end;
  1469.       char name[256];
  1470.       char BIGSTK value[8192];
  1471.       int next=0;
  1472.       name[0]=value[0]='\0';
  1473.       //
  1474.  
  1475.       // initialiser cookie lu actuellement
  1476.       if (adr)
  1477.         strcpybuff(domain,jump_identification(adr));     // domaine
  1478.       strcpybuff(path,"/");         // chemin (/)
  1479.       strcpybuff(cook_name,"");     // nom cookie (MYCOOK)
  1480.       strcpybuff(cook_value,"");    // valeur (ID=toto,S=1234)
  1481.       // boucler jusqu'au prochain cookie ou la fin
  1482.       do {
  1483.         char* start_loop=a;
  1484.         while(is_space(*a)) a++;    // sauter espaces
  1485.         token_st=a;                 // dΘpart token
  1486.         while((!is_space(*a)) && (*a) && (*a!=';') && (*a!='=')) a++;    // arrΩter si espace, point virgule
  1487.         token_end=a;
  1488.         while(is_space(*a)) a++;    // sauter espaces
  1489.         if (*a=='=') {    // name=value
  1490.           a++;
  1491.           while(is_space(*a)) a++;    // sauter espaces
  1492.           value_st=a;
  1493.           while( (*a!=';') && (*a)) a++;    // prochain ;
  1494.           //while( ((*a!='"') || (*(a-1)=='\\')) && (*a)) a++;    // prochain " (et pas \")
  1495.           value_end=a;
  1496.           //if (*a==';') {  // finit par un ;
  1497.           // vΘrifier dΘbordements
  1498.           if ( (((int) (token_end - token_st))<200) && (((int) (value_end - value_st))<8000)
  1499.             && (((int) (token_end - token_st))>0)   && (((int) (value_end - value_st))>0) ) 
  1500.           {
  1501.             int name_len = (int) (token_end - token_st);
  1502.             int value_len = (int) (value_end - value_st);
  1503.             name[0]='\0';
  1504.             value[0]='\0';
  1505.             strncatbuff(name,token_st,name_len);
  1506.             strncatbuff(value,value_st,value_len);
  1507. #if DEBUG_COOK
  1508.             printf("detected cookie-av: name=\"%s\" value=\"%s\"\n",name,value);
  1509. #endif
  1510.             if (strfield2(name,"domain")) {
  1511.               if (value_len < sizeof(domain) - 1) {
  1512.                 strcpybuff(domain,value);
  1513.               } else {
  1514.                 cook_name[0] = 0;
  1515.                 break;
  1516.               }
  1517.             }
  1518.             else if (strfield2(name,"path")) {
  1519.               if (value_len < sizeof(path) - 1) {
  1520.                 strcpybuff(path,value);
  1521.               } else {
  1522.                 cook_name[0] = 0;
  1523.                 break;
  1524.               }
  1525.             }
  1526.             else if (strfield2(name,"max-age")) {
  1527.               // ignorΘ..
  1528.             }
  1529.             else if (strfield2(name,"expires")) {
  1530.               // ignorΘ..
  1531.             }
  1532.             else if (strfield2(name,"version")) {
  1533.               // ignorΘ..
  1534.             }
  1535.             else if (strfield2(name,"comment")) {
  1536.               // ignorΘ
  1537.             }
  1538.             else if (strfield2(name,"secure")) {    // ne devrait pas arriver ici
  1539.               // ignorΘ
  1540.             }
  1541.             else {
  1542.               if (value_len < sizeof(cook_value) - 1 && name_len < sizeof(cook_name) - 1) {
  1543.                 if (strnotempty(cook_name)==0) {          // noter premier: nom et valeur cookie
  1544.                   strcpybuff(cook_name,name);
  1545.                   strcpybuff(cook_value,value);
  1546.                 } else {                             // prochain cookie
  1547.                   a=start_loop;      // on devra recommencer α cette position
  1548.                   next=1;            // enregistrer
  1549.                 }
  1550.               } else {
  1551.                 cook_name[0] = 0;
  1552.                 break;
  1553.               }
  1554.             }
  1555.           }
  1556.         }
  1557.         if (!next) {
  1558.           while((*a!=';') && (*a)) a++;    // prochain
  1559.           while(*a==';') a++;             // sauter ;
  1560.         }
  1561.       } while((*a) && (!next));
  1562.       if (strnotempty(cook_name)) {          // cookie?
  1563. #if DEBUG_COOK
  1564.         printf("new cookie: name=\"%s\" value=\"%s\" domain=\"%s\" path=\"%s\"\n",cook_name,cook_value,domain,path);
  1565. #endif
  1566.         cookie_add(cookie,cook_name,cook_value,domain,path);
  1567.       }
  1568.     }
  1569.   }
  1570. }
  1571.  
  1572.  
  1573. // transforme le message statuscode en chaεne
  1574. HTSEXT_API void infostatuscode(char* msg,int statuscode) {
  1575.   switch( statuscode) {    
  1576.     // Erreurs HTTP, selon RFC
  1577.   case 100: strcpybuff( msg,"Continue"); break; 
  1578.   case 101: strcpybuff( msg,"Switching Protocols"); break; 
  1579.   case 200: strcpybuff( msg,"OK"); break; 
  1580.   case 201: strcpybuff( msg,"Created"); break; 
  1581.   case 202: strcpybuff( msg,"Accepted"); break; 
  1582.   case 203: strcpybuff( msg,"Non-Authoritative Information"); break; 
  1583.   case 204: strcpybuff( msg,"No Content"); break; 
  1584.   case 205: strcpybuff( msg,"Reset Content"); break; 
  1585.   case 206: strcpybuff( msg,"Partial Content"); break; 
  1586.   case 300: strcpybuff( msg,"Multiple Choices"); break; 
  1587.   case 301: strcpybuff( msg,"Moved Permanently"); break; 
  1588.   case 302: strcpybuff( msg,"Moved Temporarily"); break; 
  1589.   case 303: strcpybuff( msg,"See Other"); break; 
  1590.   case 304: strcpybuff( msg,"Not Modified"); break; 
  1591.   case 305: strcpybuff( msg,"Use Proxy"); break; 
  1592.   case 306: strcpybuff( msg,"Undefined 306 error"); break; 
  1593.   case 307: strcpybuff( msg,"Temporary Redirect"); break; 
  1594.   case 400: strcpybuff( msg,"Bad Request"); break; 
  1595.   case 401: strcpybuff( msg,"Unauthorized"); break; 
  1596.   case 402: strcpybuff( msg,"Payment Required"); break; 
  1597.   case 403: strcpybuff( msg,"Forbidden"); break; 
  1598.   case 404: strcpybuff( msg,"Not Found"); break; 
  1599.   case 405: strcpybuff( msg,"Method Not Allowed"); break; 
  1600.   case 406: strcpybuff( msg,"Not Acceptable"); break; 
  1601.   case 407: strcpybuff( msg,"Proxy Authentication Required"); break; 
  1602.   case 408: strcpybuff( msg,"Request Time-out"); break; 
  1603.   case 409: strcpybuff( msg,"Conflict"); break; 
  1604.   case 410: strcpybuff( msg,"Gone"); break; 
  1605.   case 411: strcpybuff( msg,"Length Required"); break; 
  1606.   case 412: strcpybuff( msg,"Precondition Failed"); break; 
  1607.   case 413: strcpybuff( msg,"Request Entity Too Large"); break; 
  1608.   case 414: strcpybuff( msg,"Request-URI Too Large"); break; 
  1609.   case 415: strcpybuff( msg,"Unsupported Media Type"); break; 
  1610.   case 416: strcpybuff( msg,"Requested Range Not Satisfiable"); break; 
  1611.   case 417: strcpybuff( msg,"Expectation Failed"); break; 
  1612.   case 500: strcpybuff( msg,"Internal Server Error"); break; 
  1613.   case 501: strcpybuff( msg,"Not Implemented"); break; 
  1614.   case 502: strcpybuff( msg,"Bad Gateway"); break; 
  1615.   case 503: strcpybuff( msg,"Service Unavailable"); break; 
  1616.   case 504: strcpybuff( msg,"Gateway Time-out"); break; 
  1617.   case 505: strcpybuff( msg,"HTTP Version Not Supported"); break; 
  1618.     //
  1619.   default: if (strnotempty(msg)==0) strcpybuff( msg,"Unknown error"); break;
  1620.   }
  1621. }
  1622.  
  1623.  
  1624. // identique au prΘcΘdent, sauf que l'on donne adr+fil et non url complΦte
  1625. htsblk xhttpget(httrackp *opt,char* adr,char* fil) {
  1626.   T_SOC soc;
  1627.   htsblk retour;
  1628.   
  1629.   memset(&retour, 0, sizeof(htsblk));
  1630.   soc=http_fopen(opt,adr,fil,&retour);
  1631.  
  1632.   if (soc!=INVALID_SOCKET) {
  1633.     http_fread(soc,&retour);
  1634. #if HTS_DEBUG_CLOSESOCK
  1635.     DEBUG_W("xhttpget: deletehttp\n");
  1636. #endif
  1637.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1638.     retour.soc=INVALID_SOCKET;
  1639.   }
  1640.   return retour;
  1641. }
  1642.  
  1643. // variation sur un thΦme...
  1644. // rΘceptionne uniquement un en-tΩte (HEAD)
  1645. // retourne dans xx.adr l'adresse pointant sur le bloc de mΘmoire de l'en tΩte
  1646. htsblk http_gethead(httrackp *opt,char* adr,char* fil) {
  1647.   T_SOC soc;
  1648.   htsblk retour;
  1649.  
  1650.   memset(&retour, 0, sizeof(htsblk));
  1651.   soc=http_xfopen(opt,1,0,1,NULL,adr,fil,&retour);  // HEAD, pas de traitement en-tΩte
  1652.  
  1653.   if (soc!=INVALID_SOCKET) {
  1654.     http_fread(soc,&retour);    // rΘception en-tΩte
  1655. #if HTS_DEBUG_CLOSESOCK
  1656.     DEBUG_W("http_gethead: deletehttp\n");
  1657. #endif
  1658.     if (retour.soc!=INVALID_SOCKET) deletehttp(&retour);  // fermer
  1659.     retour.soc=INVALID_SOCKET;
  1660.   }
  1661.   return retour;
  1662. }
  1663. // oui ca ressemble vachement α xhttpget - en Θtant sobre on peut voir LA diffΘrence..
  1664.  
  1665.  
  1666. // lecture sur une socket ouverte, le header a dΘja ΘtΘ envoyΘ dans le cas de GET
  1667. // il ne reste plus qu'α lire les donnΘes
  1668. // (pour HEAD le header est lu ici!)
  1669. void http_fread(T_SOC soc,htsblk* retour) {  
  1670.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1671.   
  1672.   if (retour) retour->soc=soc;
  1673.   if (soc!=INVALID_SOCKET) {    
  1674.     // fonction de lecture d'une socket (plus propre)
  1675.     while(http_fread1(retour)!=-1);
  1676.     soc=retour->soc;
  1677.     if (retour->adr==NULL) {
  1678.       if (strnotempty(retour->msg)==0)
  1679.         sprintf(retour->msg,"Unable to read");
  1680.       return ;    // erreur
  1681.     } 
  1682.     
  1683. #if HDEBUG
  1684.     printf("Ok, donnΘes reτues\n");
  1685. #endif   
  1686.  
  1687.     return ;
  1688.     
  1689.   } 
  1690.   
  1691.   return ;
  1692. }
  1693.  
  1694. // check if data is available
  1695. int check_readinput(htsblk* r) {
  1696.   if (r->soc != INVALID_SOCKET) {
  1697.     fd_set fds;           // poll structures
  1698.     struct timeval tv;          // structure for select
  1699.     FD_ZERO(&fds);
  1700.     FD_SET(r->soc,&fds);           
  1701.     tv.tv_sec=0;
  1702.     tv.tv_usec=0;
  1703.     select(r->soc + 1,&fds,NULL,NULL,&tv);
  1704.     if (FD_ISSET(r->soc,&fds))
  1705.       return 1;
  1706.     else
  1707.       return 0;
  1708.   } else
  1709.     return 0;
  1710. }
  1711.  
  1712. // check if data is available
  1713. int check_readinput_t(T_SOC soc, int timeout) {
  1714.   if (soc != INVALID_SOCKET) {
  1715.     fd_set fds;           // poll structures
  1716.     struct timeval tv;          // structure for select
  1717.     FD_ZERO(&fds);
  1718.     FD_SET(soc,&fds);           
  1719.     tv.tv_sec=timeout;
  1720.     tv.tv_usec=0;
  1721.     select(soc + 1,&fds,NULL,NULL,&tv);
  1722.     if (FD_ISSET(soc,&fds))
  1723.       return 1;
  1724.     else
  1725.       return 0;
  1726.   } else
  1727.     return 0;
  1728. }
  1729.  
  1730.  
  1731. // lecture d'un bloc sur une socket (ou un fichier!)
  1732. // >=0 : nombre d'octets lus
  1733. // <0 : fin ou erreur
  1734. HTS_INLINE LLint http_fread1(htsblk* r) {
  1735.   //int bufl=TAILLE_BUFFER;  // taille d'un buffer max.
  1736.   return http_xfread1(r,TAILLE_BUFFER);
  1737. }
  1738.  
  1739. // idem, sauf qu'ici on peut choisir la taille max de donnΘes α recevoir
  1740. // SI bufl==0 alors le buffer est censΘ Ωtre de 8kos, et on recoit par bloc de lignes
  1741. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1742. // SI bufl==-1 alors le buffer est censΘ Ωtre de 8kos, et on recoit ligne par ligne
  1743. // en Θliminant les cr (ex: header), arrΩt si double-lf
  1744. // Note: les +1 dans les malloc sont d√s α l'octet nul rajoutΘ en fin de fichier
  1745. LLint http_xfread1(htsblk* r,int bufl) {
  1746.   int nl=-1;
  1747.  
  1748.   // EOF
  1749.   if (r->totalsize > 0 && r->size == r->totalsize) {
  1750.     return READ_EOF;
  1751.   }
  1752.  
  1753.   if (bufl>0) {
  1754.     if (!r->is_write) {     // stocker en mΘmoire
  1755.       if (r->totalsize>0) {    // totalsize dΘterminΘ ET ALLOUE
  1756.         if (r->adr==NULL) {
  1757.           r->adr = (char*) malloct((size_t) r->totalsize + 1);
  1758.           r->size = 0;
  1759.         }
  1760.         if (r->adr != NULL) {
  1761.           // lecture
  1762.           nl = hts_read(r,r->adr + ((int) r->size),(int) (r->totalsize-r->size) );     /* NO 32 bit overlow possible here (no 4GB html!) */
  1763.           // nouvelle taille
  1764.           if (nl >= 0) r->size+=nl;
  1765.  
  1766.           /*
  1767.           if (r->size >= r->totalsize)
  1768.             nl = -1;  // break
  1769.           */
  1770.           
  1771.           r->adr[r->size]='\0';    // caractΦre NULL en fin au cas o∙ l'on traite des HTML
  1772.         }
  1773.         
  1774.       } else {                 // inconnu..
  1775.         // rΘserver de la mΘmoire?
  1776.         if (r->adr==NULL) {
  1777. #if HDEBUG
  1778.           printf("..alloc xfread\n");
  1779. #endif
  1780.           r->adr=(char*) malloct(bufl + 1);
  1781.           r->size=0;
  1782.         }
  1783.         else {
  1784. #if HDEBUG
  1785.           printf("..realloc xfread1\n");
  1786. #endif
  1787.           r->adr=(char*) realloct(r->adr,(int)r->size+bufl + 1);
  1788.         }
  1789.         
  1790.         if (r->adr!=NULL) {
  1791.           // lecture
  1792.           nl = hts_read(r,r->adr+(int)r->size,bufl);
  1793.           if (nl > 0) {
  1794.             // resize
  1795.             r->adr=(char*) realloct(r->adr,(int)r->size+nl + 1);
  1796.             // nouvelle taille
  1797.             r->size+=nl;
  1798.             // octet nul
  1799.             if (r->adr) r->adr[r->size]='\0';
  1800.  
  1801.           } // sinon on a fini
  1802. #if HDEBUG
  1803.           else if (nl < 0)
  1804.             printf("..end read (%d)\n", nl);
  1805. #endif
  1806.         }
  1807. #if HDEBUG
  1808.         else printf("..-> error\n");
  1809. #endif
  1810.       }
  1811.  
  1812.       // pas de adr=erreur
  1813.       if (r->adr == NULL) nl = READ_ERROR;
  1814.  
  1815.     } else {    // stocker sur disque
  1816.       char* buff;
  1817.       buff=(char*) malloct(bufl);
  1818.       if (buff!=NULL) {
  1819.         // lecture
  1820.         nl = hts_read(r,buff,bufl);
  1821.         // nouvelle taille
  1822.         if (nl > 0) { 
  1823.           r->size+=nl;
  1824.           if (fwrite(buff,1,nl,r->out)!=nl) {
  1825.             r->statuscode=STATUSCODE_INVALID;
  1826.             strcpybuff(r->msg,"Write error on disk");
  1827.             nl=READ_ERROR;
  1828.           }
  1829.         }
  1830.  
  1831.         //if ((nl < 0) || ((r->totalsize>0) && (r->size >= r->totalsize)))
  1832.         //  nl=-1;  // break
  1833.  
  1834.         // libΘrer bloc tempo
  1835.         freet(buff);
  1836.       } else
  1837.         nl=READ_ERROR;
  1838.       
  1839.       if ((nl < 0) && (r->out!=NULL)) {
  1840.         fflush(r->out); 
  1841.       }
  1842.         
  1843.         
  1844.     } // stockage disque ou mΘmoire
  1845.  
  1846.   } else if (bufl == -2) {  // force reserve
  1847.     if (r->adr==NULL) {
  1848.       r->adr=(char*) malloct(8192);
  1849.       r->size=0;
  1850.       return 0;
  1851.     }
  1852.     return -1;
  1853.   } else {    // rΘception d'un en-tΩte octet par octet
  1854.     int count=256;
  1855.     int tot_nl=0;
  1856.     int lf_detected=0;
  1857.     int at_begining=1;
  1858.     do {
  1859.       nl = READ_INTERNAL_ERROR;
  1860.       count--;
  1861.       if (r->adr==NULL) {
  1862.         r->adr=(char*) malloct(8192);
  1863.         r->size=0;
  1864.       }
  1865.       if (r->adr!=NULL) {
  1866.         if (r->size < 8190) {
  1867.           // lecture
  1868.           nl = hts_read(r,r->adr+r->size,1);
  1869.           if (nl > 0) {
  1870.             // exit if:
  1871.             // lf detected AND already detected before
  1872.             // or
  1873.             // lf detected AND first character read
  1874.             if (*(r->adr+r->size) == 10) {
  1875.               if (lf_detected || (at_begining) || (bufl<0))
  1876.                 count=-1;
  1877.               lf_detected=1;
  1878.             }
  1879.             if (*(r->adr+r->size) != 13) {   // sauter caractΦres 13
  1880.               if (
  1881.                 (*(r->adr+r->size) != 10)
  1882.                 &&
  1883.                 (*(r->adr+r->size) != 13)
  1884.                 ) {
  1885.                 // restart for new line
  1886.                 lf_detected=0;
  1887.               }
  1888.               (r->size)++;
  1889.               at_begining=0;
  1890.             }
  1891.             *(r->adr+r->size)='\0';    // terminer par octet nul
  1892.           }
  1893.         }
  1894.       }
  1895.       if (nl >= 0) {
  1896.         tot_nl+=nl;
  1897.         if (!check_readinput(r))
  1898.           count=-1;
  1899.       }
  1900.     } while((nl >= 0) && (count>0));
  1901.     if (nl >= 0) {
  1902.       nl = tot_nl;
  1903.     }
  1904.   }
  1905.   // EOF
  1906.   if (r->totalsize > 0 && r->size == r->totalsize) {
  1907.     return READ_EOF;
  1908.   } else {
  1909.     return nl;
  1910.   }
  1911. }
  1912.  
  1913.  
  1914. // teste une adresse, et suit l'Θventuel chemin "moved"
  1915. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1916. // copie dans loc la vΘritable adresse si celle-ci est diffΘrente
  1917. htsblk http_location(httrackp *opt,char* adr,char* fil,char* loc) {
  1918.   htsblk retour;
  1919.   int retry=0;
  1920.   int tryagain;
  1921.   // note: "RFC says"
  1922.   // 5 boucles au plus, on en teste au plus 8 ici
  1923.   // sinon abandon..
  1924.   do {
  1925.     tryagain=0;
  1926.     switch ((retour=http_test(opt,adr,fil,loc)).statuscode) {
  1927.     case HTTP_OK:
  1928.       break;   // ok!
  1929.     case HTTP_MOVED_PERMANENTLY:
  1930.     case HTTP_FOUND:
  1931.     case HTTP_SEE_OTHER:
  1932.     case HTTP_TEMPORARY_REDIRECT: // moved!
  1933.       // recalculer adr et fil!
  1934.       if (ident_url_absolute(loc,adr,fil)!=-1) {
  1935.         tryagain=1;  // retenter
  1936.         retry++;     // ..encore une fois
  1937.       }
  1938.     }
  1939.   } while((tryagain) && (retry<5+3));
  1940.   return retour;
  1941. }
  1942.  
  1943.  
  1944. // teste si une URL (validitΘ, header, taille)
  1945. // retourne 200 ou le code d'erreur (404=NOT FOUND, etc)
  1946. // en cas de moved xx, dans location
  1947. // abandonne dΘsormais au bout de 30 secondes (aurevoir les sites
  1948. // qui nous font poireauter 5 heures..) -> -2=timeout
  1949. htsblk http_test(httrackp *opt,char* adr,char* fil,char* loc) {
  1950.   T_SOC soc;
  1951.   htsblk retour;
  1952.   //int rcvsize=-1;
  1953.   //char* rcv=NULL;    // adresse de retour
  1954.   //int bufl=TAILLE_BUFFER;    // 8Ko de buffer
  1955.   TStamp tl;
  1956.   int timeout=30;  // timeout pour un check (arbitraire) // **
  1957.  
  1958.   // pour abandonner un site trop lent
  1959.   tl=time_local();
  1960.  
  1961.   loc[0]='\0';
  1962.   memset(&retour, 0, sizeof(htsblk));    // effacer
  1963.   retour.location=loc;    // si non nul, contiendra l'adresse vΘritable en cas de moved xx
  1964.  
  1965.   //soc=http_fopen(adr,fil,&retour,NULL);  // ouvrir, + header
  1966.  
  1967.   // on ouvre en head, et on traite l'en tΩte
  1968.   soc=http_xfopen(opt,1,0,1,NULL,adr,fil,&retour);  // ouvrir HEAD, + envoi header
  1969.   
  1970.   if (soc!=INVALID_SOCKET) {
  1971.     int e=0;
  1972.     // tant qu'on a des donnΘes, et qu'on ne recoit pas deux LF, et que le timeout n'arrie pas
  1973.     do {
  1974.       if (http_xfread1(&retour,0) < 0)
  1975.         e=1;
  1976.       else {
  1977.         if (retour.adr!=NULL) {
  1978.           if ((retour.adr[retour.size-1]!=10) || (retour.adr[retour.size-2]!=10))
  1979.             e=1;
  1980.         }
  1981.       }
  1982.             
  1983.       if (!e) {
  1984.         if ((time_local()-tl)>=timeout) {
  1985.           e=-1;
  1986.         }
  1987.       }
  1988.       
  1989.     } while (!e);
  1990.     
  1991.     if (e==1) {
  1992.       if (adr!=NULL) {
  1993.         int ptr=0;
  1994.         char rcvd[1100];
  1995.  
  1996.         // note: en gros recopie du traitement de back_wait()
  1997.         //
  1998.  
  1999.  
  2000.         // ----------------------------------------
  2001.         // traiter en-tΩte!
  2002.         // status-line α rΘcupΘrer
  2003.         ptr+=binput(retour.adr+ptr,rcvd,1024);
  2004.         if (strnotempty(rcvd)==0)
  2005.           ptr+=binput(retour.adr+ptr,rcvd,1024);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  2006.         
  2007.         // traiter status-line
  2008.         treatfirstline(&retour,rcvd);
  2009.         
  2010. #if HDEBUG
  2011.         printf("(Buffer) Status-Code=%d\n",retour.statuscode);
  2012. #endif
  2013.         
  2014.         // en-tΩte
  2015.         
  2016.         // header // ** !attention! HTTP/0.9 non supportΘ
  2017.         do {
  2018.           ptr+=binput(retour.adr+ptr,rcvd,1024);          
  2019. #if HDEBUG
  2020.           printf("(buffer)>%s\n",rcvd);      
  2021. #endif
  2022.           if (strnotempty(rcvd))
  2023.             treathead(NULL,NULL,NULL,&retour,rcvd);  // traiter
  2024.           
  2025.         } while(strnotempty(rcvd));
  2026.         // ----------------------------------------                    
  2027.         
  2028.         // libΘrer mΘmoire
  2029.         if (retour.adr!=NULL) { freet(retour.adr); retour.adr=NULL; }
  2030.       }
  2031.     } else {
  2032.       retour.statuscode=STATUSCODE_TIMEOUT;
  2033.       strcpybuff(retour.msg,"Timeout While Testing");
  2034.     }
  2035.     
  2036.     
  2037. #if HTS_DEBUG_CLOSESOCK
  2038.     DEBUG_W("http_test: deletehttp\n");
  2039. #endif
  2040.     deletehttp(&retour);
  2041.     retour.soc=INVALID_SOCKET;
  2042.   }
  2043.   return retour;    
  2044. }
  2045.  
  2046. // CrΘe un lien (http) vers une adresse internet iadr
  2047. // retour: structure (adresse, taille, message si erreur (si !adr))
  2048. // peut ouvrir avec des connect() non bloquants: waitconnect=0/1
  2049. int newhttp(httrackp *opt,const char* _iadr,htsblk* retour,int port,int waitconnect) {  
  2050.   t_fullhostent fullhostent_buffer;    // buffer pour resolver
  2051.   T_SOC soc;                           // descipteur de la socket
  2052.   char* iadr;
  2053.   // unsigned short int port;
  2054.   
  2055.   // si iadr="#" alors c'est une fausse URL, mais un vrai fichier
  2056.   // local.
  2057.   // utile pour les tests!
  2058.   //## if (iadr[0]!=lOCAL_CHAR) {
  2059.   if (strcmp(_iadr,"file://") != 0) {           /* non fichier */
  2060.     SOCaddr server;
  2061.     int server_size=sizeof(server);
  2062.     t_hostent* hp;    
  2063.     // effacer structure
  2064.     memset(&server, 0, sizeof(server));
  2065.  
  2066.     // tester un Θventuel id:pass et virer id:pass@ si dΘtectΘ
  2067.     iadr = jump_identification(_iadr);
  2068.   
  2069. #if HDEBUG
  2070.     printf("gethostbyname\n");
  2071. #endif
  2072.     
  2073.     // tester un Θventuel port
  2074.     if (port==-1) {
  2075.       char *a=jump_toport(iadr);
  2076. #if HTS_USEOPENSSL
  2077.       if (retour->ssl)
  2078.         port=443;
  2079.       else
  2080.         port=80;    // port par dΘfaut
  2081. #else
  2082.       port=80;    // port par dΘfaut
  2083. #endif
  2084.       if (a) {
  2085.         char BIGSTK iadr2[HTS_URLMAXSIZE*2];
  2086.         int i=-1;
  2087.         iadr2[0]='\0';
  2088.         sscanf(a+1,"%d",&i);
  2089.         if (i!=-1) {
  2090.           port=(unsigned short int) i;
  2091.         }
  2092.         
  2093.         // adresse vΘritable (sans :xx)
  2094.         strncatbuff(iadr2,iadr,(int) (a - iadr));
  2095.  
  2096.         // adresse sans le :xx
  2097.         hp = hts_gethostbyname(opt,iadr2, &fullhostent_buffer);
  2098.         
  2099.       } else {
  2100.  
  2101.         // adresse normale (port par dΘfaut par la suite)
  2102.         hp = hts_gethostbyname(opt,iadr, &fullhostent_buffer);
  2103.         
  2104.       }
  2105.       
  2106.     } else    // port dΘfini
  2107.       hp = hts_gethostbyname(opt,iadr, &fullhostent_buffer);
  2108.  
  2109.     
  2110.     // Conversion iadr -> adresse
  2111.     // structure recevant le nom de l'h⌠te, etc
  2112.     //struct     hostent     *hp;
  2113.     if (hp == NULL) {
  2114. #if DEBUG
  2115.       printf("erreur gethostbyname\n");
  2116. #endif
  2117.       if (retour && retour->msg) {
  2118. #ifdef _WIN32
  2119.         int last_errno = WSAGetLastError();
  2120.         sprintf(retour->msg,"Unable to get server's address: %s", strerror(last_errno));
  2121. #else
  2122.         int last_errno = errno;
  2123.         sprintf(retour->msg,"Unable to get server's address: %s", strerror(last_errno));
  2124. #endif
  2125.       }
  2126.       return INVALID_SOCKET;
  2127.     }  
  2128.     // copie adresse
  2129.     SOCaddr_copyaddr(server, server_size, hp->h_addr_list[0], hp->h_length);
  2130.     // make a copy for external clients
  2131.     retour->address_size = sizeof(retour->address);
  2132.     SOCaddr_copyaddr(retour->address, retour->address_size, hp->h_addr_list[0], hp->h_length);
  2133.     // memcpy(&SOCaddr_sinaddr(server), hp->h_addr_list[0], hp->h_length);
  2134.      
  2135.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  2136. #if HDEBUG
  2137.     printf("socket\n");
  2138. #endif
  2139. #if HTS_WIDE_DEBUG    
  2140.     DEBUG_W("socket\n");
  2141. #endif
  2142.     soc = (T_SOC) socket(SOCaddr_sinfamily(server), SOCK_STREAM, 0);
  2143.     if (retour != NULL) {
  2144.       retour->debugid = HTS_STAT.stat_sockid++;
  2145.     }
  2146. #if HTS_WIDE_DEBUG    
  2147.     DEBUG_W("socket()=%d\n" _ (int) soc);
  2148. #endif
  2149.     if (soc==INVALID_SOCKET) {
  2150.       if (retour && retour->msg) {
  2151. #ifdef _WIN32
  2152.         int last_errno = WSAGetLastError();
  2153.         sprintf(retour->msg,"Unable to create a socket: %s", strerror(last_errno));
  2154. #else
  2155.         int last_errno = errno;
  2156.         sprintf(retour->msg,"Unable to create a socket: %s", strerror(last_errno));
  2157. #endif
  2158.       }
  2159.       return INVALID_SOCKET;                        // erreur crΘation socket impossible
  2160.     }
  2161.  
  2162.     // bind this address
  2163.     if (retour != NULL && retour->req.proxy.bindhost[0] != 0) {
  2164.       t_fullhostent bind_buffer;
  2165.       hp = hts_gethostbyname(opt, retour->req.proxy.bindhost, &bind_buffer);
  2166.       if (hp == NULL ||
  2167.         bind(soc, (struct sockaddr *)hp->h_addr_list[0], hp->h_length) != 0) {
  2168.           if (retour && retour->msg) {
  2169. #ifdef _WIN32
  2170.             int last_errno = WSAGetLastError();
  2171.             sprintf(retour->msg,"Unable to bind the specificied server address: %s", strerror(last_errno));
  2172. #else
  2173.             int last_errno = errno;
  2174.             sprintf(retour->msg,"Unable to bind the specificied server address: %s", strerror(last_errno));
  2175. #endif
  2176.           }
  2177.           deletesoc(soc);
  2178.           return INVALID_SOCKET;
  2179.       }
  2180.     }
  2181.     
  2182.     // structure: connexion au domaine internet, port 80 (ou autre)
  2183.     SOCaddr_initport(server, port);
  2184. #if HDEBUG
  2185.     printf("==%d\n",soc);
  2186. #endif
  2187.  
  2188.     // connexion non bloquante?
  2189.     if (!waitconnect ) {
  2190.       unsigned long p=1;  // non bloquant
  2191. #ifdef _WIN32
  2192.       ioctlsocket(soc,FIONBIO,&p);
  2193. #else
  2194.       ioctl(soc,FIONBIO,&p);
  2195. #endif
  2196.     }
  2197.     
  2198.     // Connexion au serveur lui mΩme
  2199. #if HDEBUG
  2200.     printf("connect\n");
  2201. #endif
  2202.     HTS_STAT.last_connect = mtime_local();
  2203.     
  2204. #if HTS_WIDE_DEBUG
  2205.     DEBUG_W("connect\n");
  2206. #endif
  2207. #ifdef _WIN32
  2208.     if (connect(soc, (const struct sockaddr FAR *)&server, server_size) != 0) {
  2209. #else
  2210.       if (connect(soc, (struct sockaddr *)&server, server_size) == -1) {
  2211. #endif
  2212.  
  2213.         // bloquant
  2214.         if (waitconnect) {
  2215. #if HDEBUG
  2216.           printf("unable to connect!\n");
  2217. #endif
  2218.           if (retour && retour->msg) {
  2219. #ifdef _WIN32
  2220.             int last_errno = WSAGetLastError();
  2221.             sprintf(retour->msg,"Unable to connect to the server: %s", strerror(last_errno));
  2222. #else
  2223.             int last_errno = errno;
  2224.             sprintf(retour->msg,"Unable to connect to the server: %s", strerror(last_errno));
  2225. #endif
  2226.           }
  2227.           /* Close the socket and notify the error!!! */
  2228.           deletesoc(soc);
  2229.           return INVALID_SOCKET;
  2230.         }
  2231.       }
  2232. #if HTS_WIDE_DEBUG    
  2233.       DEBUG_W("connect done\n");
  2234. #endif
  2235.       
  2236. #if HDEBUG
  2237.       printf("connexion Θtablie\n");
  2238. #endif
  2239.     
  2240.     // A partir de maintenant, on peut envoyer et recevoir des donnΘes
  2241.     // via le flot identifiΘ par soc (socket): write(soc,adr,taille) et 
  2242.     // read(soc,adr,taille)
  2243.  
  2244.   } else {    // on doit ouvrir un fichier local!
  2245.     // il sera gΘrΘ de la mΩme maniΦre qu'une socket (c'est idem!)
  2246.  
  2247.     soc=LOCAL_SOCKET_ID;    // pseudo-socket locale..
  2248.     // soc sera remplacΘ lors d'un http_fopen() par un handle vΘritable!
  2249.  
  2250.   }   // teste fichier local ou http
  2251.   
  2252.   return soc;
  2253. }
  2254.  
  2255.  
  2256.  
  2257. // couper http://www.truc.fr/pub/index.html -> www.truc.fr /pub/index.html
  2258. // retour=-1 si erreur.
  2259. // si file://... alors adresse=file:// (et coupe le ?query dans ce cas)
  2260. int ident_url_absolute(const char* url,char* adr,char* fil) {
  2261.   int pos=0;
  2262.   int scheme=0;
  2263.  
  2264.   // effacer adr et fil
  2265.   adr[0]=fil[0]='\0';
  2266.   
  2267. #if HDEBUG
  2268.   printf("protocol: %s\n",url);
  2269. #endif
  2270.  
  2271.   // Scheme?
  2272.   {
  2273.     const char* a=url;
  2274.     while (isalpha((unsigned char)*a))
  2275.       a++;
  2276.     if (*a == ':')
  2277.       scheme=1;
  2278.   }
  2279.  
  2280.   // 1. optional scheme ":"
  2281.   if ((pos=strfield(url,"file:"))) {    // fichier local!! (pour les tests)
  2282.     //!!p+=3;
  2283.     strcpybuff(adr,"file://");
  2284.   } else if ((pos=strfield(url,"http:"))) {    // HTTP
  2285.     //!!p+=3;
  2286.   } else if ((pos=strfield(url,"ftp:"))) {    // FTP
  2287.     strcpybuff(adr,"ftp://");    // FTP!!
  2288.     //!!p+=3;
  2289. #if HTS_USEOPENSSL
  2290.   } else if (SSL_is_available && (pos=strfield(url,"https:"))) {    // HTTPS
  2291.     strcpybuff(adr,"https://");
  2292. #endif
  2293. #if HTS_USEMMS
  2294.   } else if ((pos = strfield(url,"mms:"))) {    // mms
  2295.     strcpybuff(adr,"mms://");
  2296. #endif
  2297.   } else if (scheme) {
  2298.     return -1;    // erreur non reconnu
  2299.   } else
  2300.     pos=0;
  2301.  
  2302.   // 2. optional "//" authority
  2303.   if (strncmp(url+pos,"//",2)==0)
  2304.     pos+=2;
  2305.  
  2306.   // (url+pos) now points to the path (not net path)
  2307.  
  2308.   //## if (adr[0]!=lOCAL_CHAR) {    // adresse normale http
  2309.   if (!strfield(adr,"file:")) {      // PAS file://
  2310.     const char *p,*q;
  2311.     p=url+pos;
  2312.  
  2313.     // p pointe sur le dΘbut de l'adresse, ex: www.truc.fr/sommaire/index.html
  2314.     q=strchr(jump_identification(p),'/');
  2315.     if (q==0) q=strchr(jump_identification(p),'?');     // http://www.foo.com?bar=1
  2316.     if (q==0) q=p+strlen(p);  // pointe sur \0
  2317.     // q pointe sur le chemin, ex: index.html?query=recherche
  2318.     
  2319.     // chemin www... trop long!!
  2320.     if ( ( ((int) (q - p)) )  > HTS_URLMAXSIZE) {
  2321.       //strcpybuff(retour.msg,"Path too long");
  2322.       return -1;    // erreur
  2323.     }
  2324.     
  2325.     // recopier adresse www..
  2326.     strncatbuff(adr,p, ((int) (q - p)) );
  2327.     // *( adr+( ((int) q) - ((int) p) ) )=0;  // faut arrΩter la fumette!
  2328.     // recopier chemin /pub/..
  2329.     if (q[0] != '/')    // page par dΘfaut (/)
  2330.       strcatbuff(fil,"/");
  2331.     strcatbuff(fil,q);
  2332.     // SECURITE:
  2333.     // simplifier url pour les ../
  2334.     fil_simplifie(fil);
  2335.   } else {    // localhost file://
  2336.     const char *p;
  2337.     int i;
  2338.     char* a;
  2339.     
  2340.     p=url+pos;
  2341.     if (*p == '/' || *p == '\\') {  /* file:///.. */
  2342.       strcatbuff(fil,p);    // fichier local ; adr="#"
  2343.     } else {
  2344.       if (p[1] != ':') {
  2345.         strcatbuff(fil,"//");   /* file://server/foo */
  2346.         strcatbuff(fil,p);
  2347.       } else {
  2348.         strcatbuff(fil,p);    // file://C:\..
  2349.       }
  2350.     }
  2351.     
  2352.     a=strchr(fil,'?');
  2353.     if (a) 
  2354.       *a='\0';      /* couper query (inutile pour file:// lors de la requΩte) */
  2355.     // filtrer les \\ -> / pour les fichiers DOS
  2356.     for(i=0;i<(int) strlen(fil);i++)
  2357.       if (fil[i]=='\\')
  2358.         fil[i]='/';
  2359.   }
  2360.  
  2361.   // no hostname
  2362.   if (!strnotempty(adr))
  2363.     return -1;    // erreur non reconnu
  2364.  
  2365.   // nommer au besoin.. (non utilisΘ normalement)
  2366.   if (!strnotempty(fil))
  2367.     strcpybuff(fil,"default-index.html");
  2368.  
  2369.   // case insensitive pour adresse
  2370.   {
  2371.     char *a=jump_identification(adr);
  2372.     while(*a) {
  2373.       if ((*a>='A') && (*a<='Z'))
  2374.         *a+='a'-'A';       
  2375.       a++;
  2376.     }
  2377.   }
  2378.   
  2379.   return 0;
  2380. }
  2381.  
  2382. /* simplify ../ and ./ */
  2383. void fil_simplifie(char* f) {
  2384.   char *a, *b;
  2385.   char *rollback[128];
  2386.   int rollid = 0;
  2387.   char lc = '/';
  2388.   int query = 0;
  2389.   int wasAbsolute = (*f == '/');
  2390.   for(a = b = f ; *a != '\0' ; ) {
  2391.     if (*a == '?')
  2392.       query = 1;
  2393.     if (query == 0 && lc == '/' && a[0] == '.' && a[1] == '/') {    /* foo/./bar or ./foo  */
  2394.       a += 2;
  2395.     }
  2396.     else if (query == 0 && lc == '/' && a[0] == '.' && a[1] == '.' && ( a[2] == '/' || a[2] == '\0' ) ) {    /* foo/../bar or ../foo or .. */
  2397.       if (a[2] == '\0')
  2398.         a += 2;
  2399.       else
  2400.         a += 3;
  2401.       if (rollid > 1) {
  2402.         rollid--;
  2403.         b = rollback[rollid - 1];
  2404.       } else {   /* too many ../ */
  2405.         rollid = 0;
  2406.         b = f;
  2407.         if (wasAbsolute)
  2408.           b++;   /* after the / */
  2409.       }
  2410.     }
  2411.     else {
  2412.       *b++ = lc = *a;
  2413.       if (*a == '/') {
  2414.         rollback[rollid++] = b;
  2415.         if (rollid >= 127) {
  2416.           *f = '\0';      /* ERROR */
  2417.           break;
  2418.         }
  2419.       }
  2420.       a++;
  2421.     }
  2422.   }
  2423.   *b = '\0';
  2424.   if (*f == '\0') {
  2425.     if (wasAbsolute) {
  2426.       f[0] = '/';
  2427.       f[1] = '\0';
  2428.     } else {
  2429.       f[0] = '.';
  2430.       f[1] = '/';
  2431.       f[2] = '\0';
  2432.     }
  2433.   }
  2434. }
  2435.  
  2436. // fermer liaison fichier ou socket
  2437. HTS_INLINE void deletehttp(htsblk* r) {
  2438. #if HTS_DEBUG_CLOSESOCK
  2439.     DEBUG_W("deletehttp: (htsblk*) 0x%p\n" _ (void*) r);
  2440. #endif
  2441. #if HTS_USEOPENSSL
  2442.     /* Free OpenSSL structures */
  2443.     if (SSL_is_available && r->ssl_con) {
  2444.       SSL_shutdown(r->ssl_con);
  2445.       SSL_free(r->ssl_con);
  2446.       r->ssl_con=NULL;
  2447.     }
  2448. #endif  
  2449.   if (r->soc!=INVALID_SOCKET) {
  2450.     if (r->is_file) {
  2451.       if (r->fp)
  2452.         fclose(r->fp);
  2453.       r->fp=NULL;
  2454.     } else {
  2455.       if (r->soc!=LOCAL_SOCKET_ID)
  2456.         deletesoc_r(r);
  2457.     }
  2458.     r->soc=INVALID_SOCKET;
  2459.   }
  2460. }
  2461.  
  2462. // free the addr buffer
  2463. // always returns 1
  2464. HTS_INLINE int deleteaddr(htsblk* r) {
  2465.   if (r->adr != NULL) {
  2466.     freet(r->adr);
  2467.     r->adr = NULL;
  2468.   }
  2469.   if (r->headers != NULL) {
  2470.     freet(r->headers);
  2471.     r->headers = NULL;
  2472.   }
  2473.   return 1;
  2474. }
  2475.  
  2476. // fermer une socket
  2477. HTS_INLINE void deletesoc(T_SOC soc) {
  2478.   if (soc!=INVALID_SOCKET && soc!=LOCAL_SOCKET_ID) {
  2479. #if HTS_WIDE_DEBUG    
  2480.     DEBUG_W("close %d\n" _ (int) soc);
  2481. #endif
  2482. #ifdef _WIN32
  2483.     closesocket(soc);
  2484. #else
  2485.     close(soc);
  2486. #endif
  2487. #if HTS_WIDE_DEBUG    
  2488.     DEBUG_W(".. done\n");
  2489. #endif
  2490.   }
  2491. }
  2492.  
  2493. /* Will also clean other things */
  2494. HTS_INLINE void deletesoc_r(htsblk* r) {
  2495. #if HTS_USEOPENSSL
  2496.   if (SSL_is_available && r->ssl_con) {
  2497.     SSL_shutdown(r->ssl_con);
  2498.     // SSL_CTX_set_quiet_shutdown(r->ssl_con->ctx, 1);
  2499.     SSL_free(r->ssl_con);
  2500.     r->ssl_con=NULL;
  2501.   }
  2502. #endif
  2503.   if (r->soc!=INVALID_SOCKET) {
  2504.     deletesoc(r->soc);
  2505.     r->soc=INVALID_SOCKET;
  2506.   }
  2507. }
  2508.  
  2509. // renvoi le nombre de secondes depuis 1970
  2510. HTS_INLINE TStamp time_local(void) {
  2511.   return ((TStamp) time(NULL));
  2512. }
  2513.  
  2514. // number of millisec since 1970
  2515. HTSEXT_API HTS_INLINE TStamp mtime_local(void) {
  2516. #ifndef HTS_DO_NOT_USE_FTIME
  2517.   struct timeb B;
  2518.   ftime( &B );
  2519.   return (TStamp) ( ((TStamp) B.time * (TStamp) 1000)
  2520.         + ((TStamp) B.millitm) );
  2521. #else
  2522.   // not precise..
  2523.   return (TStamp) ( ((TStamp) time_local() * (TStamp) 1000)
  2524.         + ((TStamp) 0) );
  2525. #endif
  2526. }
  2527.  
  2528. // convertit un nombre de secondes en temps (chaine)
  2529. void sec2str(char *st,TStamp t) {
  2530.   int j,h,m,s;
  2531.   
  2532.   j=(int) (t/(3600*24));
  2533.   t-=((TStamp) j)*(3600*24);
  2534.   h=(int) (t/(3600));
  2535.   t-=((TStamp) h)*3600;
  2536.   m=(int) (t/60);
  2537.   t-=((TStamp) m)*60;
  2538.   s=(int) t;
  2539.   
  2540.   if (j>0)
  2541.     sprintf(st,"%d days, %d hours %d minutes %d seconds",j,h,m,s);
  2542.   else if (h>0)
  2543.     sprintf(st,"%d hours %d minutes %d seconds",h,m,s);
  2544.   else if (m>0)
  2545.     sprintf(st,"%d minutes %d seconds",m,s);
  2546.   else
  2547.     sprintf(st,"%d seconds",s);
  2548. }
  2549.  
  2550. // idem, plus court (chaine)
  2551. HTSEXT_API void qsec2str(char *st,TStamp t) {
  2552.   int j,h,m,s;
  2553.   
  2554.   j=(int) (t/(3600*24));
  2555.   t-=((TStamp) j)*(3600*24);
  2556.   h=(int) (t/(3600));
  2557.   t-=((TStamp) h)*3600;
  2558.   m=(int) (t/60);
  2559.   t-=((TStamp) m)*60;
  2560.   s=(int) t;
  2561.   
  2562.   if (j>0)
  2563.     sprintf(st,"%dd,%02dh,%02dmin%02ds",j,h,m,s);
  2564.   else if (h>0)
  2565.     sprintf(st,"%dh,%02dmin%02ds",h,m,s);
  2566.   else if (m>0)
  2567.     sprintf(st,"%dmin%02ds",m,s);
  2568.   else
  2569.     sprintf(st,"%ds",s);
  2570. }
  2571.  
  2572.  
  2573. // heure actuelle, GMT, format rfc (taille buffer 256o)
  2574. void time_gmt_rfc822(char* s) {
  2575.   time_t tt;
  2576.   struct tm* A;
  2577.   tt=time(NULL);
  2578.   A=gmtime(&tt);
  2579.   if (A==NULL)
  2580.     A=localtime(&tt);
  2581.   time_rfc822(s,A);
  2582. }
  2583.  
  2584. // heure actuelle, format rfc (taille buffer 256o)
  2585. void time_local_rfc822(char* s) {
  2586.   time_t tt;
  2587.   struct tm* A;
  2588.   tt=time(NULL);
  2589.   A=localtime(&tt);
  2590.   time_rfc822_local(s,A);
  2591. }
  2592.  
  2593. /* convertir une chaine en temps */
  2594. struct tm* convert_time_rfc822(struct tm *result, const char* s) {
  2595.   char months[]="jan feb mar apr may jun jul aug sep oct nov dec";
  2596.   char str[256];
  2597.   char* a;
  2598.   /* */
  2599.   int result_mm=-1;
  2600.   int result_dd=-1;
  2601.   int result_n1=-1;
  2602.   int result_n2=-1;
  2603.   int result_n3=-1;
  2604.   int result_n4=-1;
  2605.   /* */
  2606.  
  2607.   if ((int) strlen(s) > 200)
  2608.     return NULL;
  2609.   strcpybuff(str,s);
  2610.   hts_lowcase(str);
  2611.   /* Θliminer :,- */
  2612.   while( (a=strchr(str,'-')) ) *a=' ';
  2613.   while( (a=strchr(str,':')) ) *a=' ';
  2614.   while( (a=strchr(str,',')) ) *a=' ';
  2615.   /* tokeniser */
  2616.   a=str;
  2617.   while(*a) {
  2618.     char *first,*last;
  2619.     char tok[256];
  2620.     /* dΘcouper mot */
  2621.     while(*a==' ') a++;   /* sauter espaces */
  2622.     first=a;
  2623.     while((*a) && (*a!=' ')) a++;
  2624.     last=a;
  2625.     tok[0]='\0';
  2626.     if (first!=last) {
  2627.       char* pos;
  2628.       strncatbuff(tok,first,(int) (last - first));
  2629.       /* analyser */
  2630.       if ( (pos=strstr(months,tok)) ) {               /* month always in letters */
  2631.         result_mm=((int) (pos - months))/4;
  2632.       } else {
  2633.         int number;
  2634.         if (sscanf(tok,"%d",&number) == 1) {      /* number token */
  2635.           if (result_dd<0)                        /* day always first number */
  2636.             result_dd=number;
  2637.           else if (result_n1<0)
  2638.             result_n1=number;
  2639.           else if (result_n2<0)
  2640.             result_n2=number;
  2641.           else if (result_n3<0)
  2642.             result_n3=number;
  2643.           else if (result_n4<0)
  2644.             result_n4=number;
  2645.         }   /* sinon, bruit de fond(+1GMT for exampel) */
  2646.       }
  2647.     }
  2648.   }
  2649.   if ((result_n1>=0) && (result_mm>=0) && (result_dd>=0) && (result_n2>=0) && (result_n3>=0) && (result_n4>=0)) {
  2650.     if (result_n4>=1000) {               /* Sun Nov  6 08:49:37 1994 */
  2651.       result->tm_year=result_n4-1900;
  2652.       result->tm_hour=result_n1;
  2653.       result->tm_min=result_n2;
  2654.       result->tm_sec=max(result_n3,0);
  2655.     } else {                            /* Sun, 06 Nov 1994 08:49:37 GMT or Sunday, 06-Nov-94 08:49:37 GMT */
  2656.       result->tm_hour=result_n2;
  2657.       result->tm_min=result_n3;
  2658.       result->tm_sec=max(result_n4,0);
  2659.       if (result_n1<=50)                /* 00 means 2000 */
  2660.         result->tm_year=result_n1+100;
  2661.       else if (result_n1<1000)          /* 99 means 1999 */
  2662.         result->tm_year=result_n1;
  2663.       else                              /* 2000 */
  2664.         result->tm_year=result_n1-1900;
  2665.     }
  2666.     result->tm_isdst=0;        /* assume GMT */
  2667.     result->tm_yday=-1;        /* don't know */
  2668.     result->tm_wday=-1;        /* don't know */
  2669.     result->tm_mon=result_mm;
  2670.     result->tm_mday=result_dd;
  2671.     return result;
  2672.   }
  2673.   return NULL;
  2674. }
  2675.  
  2676. static time_t getGMT(struct tm *tm) {        /* hey, time_t is local! */
  2677.     time_t t = mktime(tm);
  2678.     if (t != (time_t) -1 && t != (time_t) 0) {
  2679.     /* BSD does not have static "timezone" declared */
  2680. #if (defined(BSD) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD_kernel__))
  2681.     time_t now = time(NULL); 
  2682.     time_t timezone = - localtime(&now)->tm_gmtoff;
  2683. #endif
  2684.     return (time_t) (t - timezone);
  2685.     }
  2686.     return (time_t) -1;
  2687. }
  2688.  
  2689. /* sets file time. -1 if error */
  2690. int set_filetime(const char* file, struct tm* tm_time) {
  2691.     time_t t = getGMT(tm_time);
  2692.     if (t != (time_t) -1) {
  2693.       struct utimbuf tim;
  2694.         memset(&tim, 0, sizeof(tim));
  2695.       tim.actime = tim.modtime = t; 
  2696.         return utime(file, &tim);
  2697.     }
  2698.     return -1;
  2699. }
  2700.  
  2701. /* sets file time from RFC822 date+time, -1 if error*/
  2702. int set_filetime_rfc822(const char* file, const char* date) {
  2703.     struct tm buffer;
  2704.   struct tm* tm_s = convert_time_rfc822(&buffer, date);
  2705.   if (tm_s) {
  2706.     return set_filetime(file,tm_s);
  2707.   } else return -1;
  2708. }
  2709.  
  2710. int get_filetime_rfc822(const char* file, char* date) {
  2711.   struct stat buf;
  2712.   date[0] = '\0';
  2713.   if (stat(file, &buf) == 0) {
  2714.     struct tm* A;
  2715.     time_t tt = buf.st_mtime;
  2716.     A=gmtime(&tt);
  2717.     if (A==NULL)
  2718.       A=localtime(&tt);
  2719.     if (A != NULL) {
  2720.       time_rfc822(date, A);
  2721.       return 1;
  2722.     }
  2723.   }
  2724.   return 0;
  2725. }
  2726.  
  2727. // heure au format rfc (taille buffer 256o)
  2728. HTS_INLINE void time_rfc822(char* s,struct tm * A) {
  2729.   if (A == NULL) {
  2730.     int localtime_returned_null=0;
  2731.     assert(localtime_returned_null);
  2732.   }
  2733.   strftime(s,256,"%a, %d %b %Y %H:%M:%S GMT",A);
  2734. }
  2735.  
  2736. // heure locale au format rfc (taille buffer 256o)
  2737. HTS_INLINE void time_rfc822_local(char* s,struct tm * A) {
  2738.   if (A == NULL) {
  2739.     int localtime_returned_null=0;
  2740.     assert(localtime_returned_null);
  2741.   }
  2742.   strftime(s,256,"%a, %d %b %Y %H:%M:%S",A);
  2743. }
  2744.  
  2745. // conversion en b,Kb,Mb
  2746. HTSEXT_API char* int2bytes(strc_int2bytes2* strc, LLint n) {
  2747.   char** a = int2bytes2(strc, n);
  2748.   strcpybuff(strc->catbuff, a[0]);
  2749.   strcatbuff(strc->catbuff, a[1]);
  2750.   return strc->catbuff;
  2751. }
  2752.  
  2753. // conversion en b/s,Kb/s,Mb/s
  2754. HTSEXT_API char* int2bytessec(strc_int2bytes2* strc, long int n) {
  2755.     char buff[256];
  2756.   char** a = int2bytes2(strc, n);
  2757.   strcpybuff(buff, a[0]);
  2758.   strcatbuff(buff, a[1]);
  2759.   return concat(strc->catbuff, buff, "/s");
  2760. }
  2761. HTSEXT_API char* int2char(strc_int2bytes2* strc, int n) {
  2762.   sprintf(strc->buff2, "%d", n);
  2763.   return strc->buff2;
  2764. }
  2765.  
  2766. // conversion en b,Kb,Mb, nombre et type sΘparΘs
  2767. // limite: 2.10^9.10^6B
  2768.  
  2769. /* See http://physics.nist.gov/cuu/Units/binary.html */
  2770. #define ToLLint(a) ((LLint)(a))
  2771. #define ToLLintKiB (ToLLint(1024))
  2772. #define ToLLintMiB (ToLLintKiB*ToLLintKiB)
  2773. #ifdef HTS_LONGLONG
  2774. #define ToLLintGiB (ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2775. #define ToLLintTiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2776. #define ToLLintPiB (ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB*ToLLintKiB)
  2777. #endif
  2778. HTSEXT_API char** int2bytes2(strc_int2bytes2* strc, LLint n) {
  2779.   if (n < ToLLintKiB) {
  2780.     sprintf(strc->buff1,"%d",(int)(LLint)n);
  2781.     strcpybuff(strc->buff2,"B");
  2782.   } else if (n < ToLLintMiB) {
  2783.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/ToLLintKiB)),(int)((LLint)((n%ToLLintKiB)*100)/ToLLintKiB));
  2784.     strcpybuff(strc->buff2,"KiB");
  2785.   }
  2786. #ifdef HTS_LONGLONG
  2787.   else if (n < ToLLintGiB) {
  2788.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2789.     strcpybuff(strc->buff2,"MiB");
  2790.   } else if (n < ToLLintTiB) {
  2791.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintGiB))),(int)((LLint)(((n%(ToLLintGiB))*100)/(ToLLintGiB))));
  2792.     strcpybuff(strc->buff2,"GiB");
  2793.   } else if (n < ToLLintPiB) {
  2794.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintTiB))),(int)((LLint)(((n%(ToLLintTiB))*100)/(ToLLintTiB))));
  2795.     strcpybuff(strc->buff2,"TiB");
  2796.   } else {
  2797.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintPiB))),(int)((LLint)(((n%(ToLLintPiB))*100)/(ToLLintPiB))));
  2798.     strcpybuff(strc->buff2,"PiB");
  2799.   }
  2800. #else
  2801.   else {
  2802.     sprintf(strc->buff1,"%d,%02d",(int)((LLint)(n/(ToLLintMiB))),(int)((LLint)(((n%(ToLLintMiB))*100)/(ToLLintMiB))));
  2803.     strcpybuff(strc->buff2,"MiB");
  2804.   }
  2805. #endif
  2806.   strc->buffadr[0]=strc->buff1;
  2807.   strc->buffadr[1]=strc->buff2;
  2808.   return strc->buffadr;
  2809. }
  2810.  
  2811. #ifdef _WIN32
  2812. #else
  2813. // ignore sigpipe?
  2814. int sig_ignore_flag( int setflag ) {     // flag ignore
  2815.   static int flag=0;   /* YES, this one is true static */
  2816.   if (setflag>=0)
  2817.     flag=setflag;
  2818.   return flag;
  2819. }
  2820. #endif
  2821.  
  2822. // envoi de texte (en tΩtes gΘnΘralement) sur la socket soc
  2823. HTS_INLINE int sendc(htsblk* r, const char* s) {
  2824.   int n, ssz = (int)strlen(s);
  2825.  
  2826. #ifdef _WIN32
  2827. #else
  2828.   sig_ignore_flag(1);
  2829. #endif
  2830. #if HDEBUG
  2831.   write(0,s,ssz);
  2832. #endif
  2833.  
  2834. #if HTS_USEOPENSSL
  2835.   if (SSL_is_available && r->ssl) {
  2836.     n = SSL_write(r->ssl_con, s, ssz);
  2837.   } else
  2838. #endif
  2839.     n = send(r->soc,s,ssz,0);
  2840.  
  2841. #ifdef _WIN32
  2842. #else
  2843.   sig_ignore_flag(0);
  2844. #endif
  2845.  
  2846.   return ( n == ssz ) ? n : -1;
  2847. }
  2848.  
  2849.  
  2850. // Remplace read
  2851. int finput(int fd,char* s,int max) {
  2852.   char c;
  2853.   int j=0;
  2854.   do {
  2855.     //c=fgetc(fp);
  2856.     if (read(fd,&c,1)<=0) {
  2857.       c=0;
  2858.     }
  2859.     if (c!=0) {
  2860.       switch(c) {
  2861.       case 10: c=0; break;
  2862.       case 13: break;  // sauter ces caractΦres
  2863.       default: s[j++]=c; break;
  2864.       }
  2865.     }
  2866.   }  while((c!=0) && (j<max-1));
  2867.   s[j]='\0';
  2868.   return j;
  2869.  
  2870. // Like linput, but in memory (optimized)
  2871. int binput(char* buff, char* s, int max) {
  2872.   int count = 0;
  2873.   int destCount = 0;
  2874.  
  2875.   // Note: \0 will return 1
  2876.   while(destCount < max && buff != NULL && buff[count] != '\0' && buff[count] != '\n') {
  2877.     if (buff[count] != '\r') {
  2878.       s[destCount++] = buff[count];
  2879.     }
  2880.     count++;
  2881.   }
  2882.   s[destCount] = '\0';
  2883.  
  2884.   // then return the supplemental jump offset
  2885.   return count + 1;
  2886.  
  2887. // Lecture d'une ligne (peut Ωtre unicode α priori)
  2888. int linput(FILE* fp,char* s,int max) {
  2889.   int c;
  2890.   int j=0;
  2891.   do {
  2892.     c=fgetc(fp);
  2893.     if (c!=EOF) {
  2894.       switch(c) {
  2895.         case 13: break;  // sauter CR
  2896.         case 10: c=-1; break;
  2897.         case 9: case 12: break;  // sauter ces caractΦres
  2898.         default: s[j++]=(char) c; break;
  2899.       }
  2900.     }
  2901.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2902.   s[j]='\0';
  2903.   return j;
  2904. }
  2905. int linputsoc(T_SOC soc, char* s, int max) {
  2906.   int c;
  2907.   int j=0;
  2908.   do {
  2909.     unsigned char ch;
  2910.     if (recv(soc, &ch, 1, 0) == 1) {
  2911.       c = ch;
  2912.     } else {
  2913.       c = EOF;
  2914.     }
  2915.     if (c!=EOF) {
  2916.       switch(c) {
  2917.         case 13: break;  // sauter CR
  2918.         case 10: c=-1; break;
  2919.         case 9: case 12: break;  // sauter ces caractΦres
  2920.         default: s[j++]=(char) c; break;
  2921.       }
  2922.     }
  2923.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2924.   s[j]='\0';
  2925.   return j;
  2926. }
  2927. int linputsoc_t(T_SOC soc, char* s, int max, int timeout) {
  2928.   if (check_readinput_t(soc, timeout)) {
  2929.     return linputsoc(soc, s, max);
  2930.   }
  2931.   return -1;
  2932. }
  2933. int linput_trim(FILE* fp,char* s,int max) {
  2934.   int rlen=0;
  2935.   char* ls=(char*) malloct(max+2);
  2936.   s[0]='\0';
  2937.   if (ls) {
  2938.     char* a;
  2939.     // lire ligne
  2940.     rlen=linput(fp,ls,max);
  2941.     if (rlen) {
  2942.       // sauter espaces et tabs en fin
  2943.       while( (rlen>0) && ((ls[max(rlen-1,0)]==' ') || (ls[max(rlen-1,0)]=='\t')) )
  2944.         ls[--rlen]='\0';
  2945.       // sauter espaces en dΘbut
  2946.       a=ls;
  2947.       while((rlen>0) && ((*a==' ') || (*a=='\t'))) {
  2948.         a++;
  2949.         rlen--;
  2950.       }
  2951.       if (rlen>0) {
  2952.         memcpy(s,a,rlen);      // can copy \0 chars
  2953.         s[rlen]='\0';
  2954.       }
  2955.     }
  2956.     //
  2957.     freet(ls);
  2958.   }
  2959.   return rlen;
  2960. }
  2961. int linput_cpp(FILE* fp,char* s,int max) {
  2962.   int rlen=0;
  2963.   s[0]='\0';
  2964.   do {
  2965.     int ret;
  2966.     if (rlen>0)
  2967.     if (s[rlen-1]=='\\')
  2968.       s[--rlen]='\0';      // couper \ final
  2969.     // lire ligne
  2970.     ret=linput_trim(fp,s+rlen,max-rlen);
  2971.     if (ret>0)
  2972.       rlen+=ret;
  2973.   } while((s[max(rlen-1,0)]=='\\') && (rlen<max));
  2974.   return rlen;
  2975. }
  2976.  
  2977. // idem avec les car spΘciaux
  2978. void rawlinput(FILE* fp,char* s,int max) {
  2979.   int c;
  2980.   int j=0;
  2981.   do {
  2982.     c=fgetc(fp);
  2983.     if (c!=EOF) {
  2984.       switch(c) {
  2985.         case 13: break;  // sauter CR
  2986.         case 10: c=-1; break;
  2987.         default: s[j++]=(char) c; break;
  2988.       }
  2989.     }
  2990.   }  while((c!=-1) && (c!=EOF) && (j<(max-1)));
  2991.   s[j++]='\0';
  2992. }
  2993.  
  2994. //cherche chaine, case insensitive
  2995. char* strstrcase(char *s,char *o) {
  2996.   while((*s) && (strfield(s,o)==0)) s++;
  2997.   if (*s=='\0') return NULL;
  2998.   return s;  
  2999. }
  3000.  
  3001.  
  3002. // Unicode detector
  3003. // See http://www.unicode.org/unicode/reports/tr28/
  3004. // (sect Table 3.1B. Legal UTF-8 Byte Sequences)
  3005. typedef struct {
  3006.   unsigned int pos;
  3007.   unsigned char data[4];
  3008. } t_auto_seq;
  3009.  
  3010. // char between a and b
  3011. #define CHAR_BETWEEN(c, a, b)       ( (c) >= 0x##a ) && ( (c) <= 0x##b )
  3012. // sequence start
  3013. #define SEQBEG                      ( inseq == 0 )
  3014. // in this block
  3015. #define BLK(n,a, b)                 ( (seq.pos >= n) && ((err = CHAR_BETWEEN(seq.data[n], a, b))) )
  3016. #define ELT(n,a)                    BLK(n,a,a)
  3017. // end
  3018. #define SEQEND                      ((ok = 1))
  3019. // sequence started, character will fail if error
  3020. #define IN_SEQ                      ( (inseq = 1) )
  3021. // decoding error
  3022. #define BAD_SEQ                     ( (ok == 0) && (inseq != 0) && (!err) )
  3023. // no sequence started
  3024. #define NO_SEQ                      ( inseq == 0 )
  3025.  
  3026. // is this block an UTF unicode textfile?
  3027. // 0 : no
  3028. // 1 : yes
  3029. // -1: don't know
  3030. int is_unicode_utf8(unsigned char* buffer, unsigned int size) {
  3031.   t_auto_seq seq;
  3032.   unsigned int i;
  3033.   int is_utf=-1;
  3034.  
  3035.   seq.pos=0;
  3036.   for(i=0 ; i < size ; i++) {
  3037.     unsigned int ok=0;
  3038.     unsigned int inseq=0;
  3039.     unsigned int err=0;
  3040.  
  3041.     seq.data[seq.pos]=buffer[i];
  3042.     /**/ if ( SEQBEG && BLK(0,00,7F) && IN_SEQ && SEQEND                                                 ) { }
  3043.     else if ( SEQBEG && BLK(0,C2,DF) && IN_SEQ && BLK(1,80,BF) && SEQEND                                 ) { }
  3044.     else if ( SEQBEG && ELT(0,E0   ) && IN_SEQ && BLK(1,A0,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  3045.     else if ( SEQBEG && BLK(0,E1,EC) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  3046.     else if ( SEQBEG && ELT(0,ED   ) && IN_SEQ && BLK(1,80,9F) && BLK(2,80,BF) && SEQEND                 ) { }
  3047.     else if ( SEQBEG && BLK(0,EE,EF) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && SEQEND                 ) { }
  3048.     else if ( SEQBEG && ELT(0,F0   ) && IN_SEQ && BLK(1,90,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  3049.     else if ( SEQBEG && BLK(0,F1,F3) && IN_SEQ && BLK(1,80,BF) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  3050.     else if ( SEQBEG && ELT(0,F4   ) && IN_SEQ && BLK(1,80,8F) && BLK(2,80,BF) && BLK(3,80,BF) && SEQEND ) { }
  3051.     else if ( NO_SEQ ) {    // bad, unknown
  3052.       return 0;
  3053.     }
  3054.     /* */
  3055.     
  3056.     /* Error */
  3057.     if ( BAD_SEQ ) {
  3058.       return 0;
  3059.     }
  3060.  
  3061.     /* unicode character */
  3062.     if (seq.pos > 0)
  3063.       is_utf=1;
  3064.  
  3065.     /* Next */
  3066.     if (ok)
  3067.       seq.pos=0;
  3068.     else
  3069.       seq.pos++;
  3070.  
  3071.     /* Internal error */
  3072.     if (seq.pos >= 4)
  3073.       return 0;
  3074.  
  3075.   }
  3076.  
  3077.   return is_utf;
  3078. }
  3079.  
  3080. void map_characters(unsigned char* buffer, unsigned int size, unsigned int* map) {
  3081.   unsigned int i;
  3082.   memset(map, 0, sizeof(unsigned int) * 256);
  3083.   for(i = 0 ; i < size ; i++) {
  3084.     map[buffer[i]]++;
  3085.   }
  3086. }
  3087.  
  3088.  
  3089. // le fichier est-il un fichier html?
  3090. //  0 : non
  3091. //  1 : oui
  3092. // -1 : on sait pas
  3093. // -2 : on sait pas, pas d'extension
  3094. int ishtml(httrackp *opt,const char* fil) {
  3095.   /* User-defined MIME types (overrides ishtml()) */
  3096.   char BIGSTK fil_noquery[HTS_URLMAXSIZE*2];
  3097.   char mime[256];
  3098.   char* a;
  3099.   strcpybuff(fil_noquery, fil);
  3100.   if ((a = strchr(fil_noquery, '?')) != NULL) {
  3101.     *a = '\0';
  3102.   }
  3103.   if (get_userhttptype(opt, mime, fil_noquery)) {
  3104.     if (strfield2(mime, "text/html")) {
  3105.       return 1;
  3106.     } else {
  3107.       return 0;
  3108.     }
  3109.   }
  3110.  
  3111.   if (!strnotempty(fil_noquery)) {
  3112.     return -2;
  3113.   }
  3114.  
  3115.   /* Search for known ext */
  3116.   for (a = fil_noquery + strlen(fil_noquery) - 1 ; *a != '.' && *a != '/' && a > fil_noquery ; a-- );
  3117.   if (*a == '.') {  // a une extension
  3118.     char BIGSTK fil_noquery[HTS_URLMAXSIZE*2];
  3119.     char* b;
  3120.     int ret;
  3121.     char* dotted = a;
  3122.     fil_noquery[0]='\0';
  3123.     a++;  // pointer sur extension
  3124.     strncatbuff(fil_noquery,a,HTS_URLMAXSIZE);
  3125.     b=strchr(fil_noquery,'?');
  3126.     if (b)
  3127.       *b='\0';
  3128.     ret = ishtml_ext(fil_noquery);     // retour
  3129.     if (ret == -1) {
  3130.       switch(is_knowntype(opt,dotted)) {
  3131.       case 1:
  3132.         ret = 0;     // connu, non html
  3133.         break;
  3134.       case 2:
  3135.         ret = 1;     // connu, html
  3136.         break;
  3137.       default:
  3138.         ret = -1;    // inconnu..
  3139.         break;
  3140.       }
  3141.     }
  3142.     return ret;
  3143.   } else return -2;   // indΘterminΘ, par exemple /truc
  3144. }
  3145.  
  3146. // idem, mais pour uniquement l'extension
  3147. int ishtml_ext(const char* a) {
  3148.   int html=0;  
  3149.   //
  3150.   if (strfield2(a,"html"))       html = 1;
  3151.   else if (strfield2(a,"htm"))   html = 1;
  3152.   else if (strfield2(a,"shtml")) html = 1;
  3153.   else if (strfield2(a,"phtml")) html = 1;
  3154.   else if (strfield2(a,"htmlx")) html = 1;
  3155.   else if (strfield2(a,"shtm"))  html = 1;
  3156.   else if (strfield2(a,"phtm"))  html = 1;
  3157.   else if (strfield2(a,"htmx"))  html = 1;
  3158.   //
  3159.   // insuccΦs..
  3160.   else {
  3161. #if 1
  3162.     html = -1;    // inconnu..
  3163. #else
  3164.     // XXXXXX not suitable (ext)
  3165.     switch(is_knownext(a)) {
  3166.     case 1:
  3167.       html = 0;     // connu, non html
  3168.       break;
  3169.     case 2:
  3170.       html = 1;     // connu, html
  3171.       break;
  3172.     default:
  3173.       html = -1;    // inconnu..
  3174.       break;
  3175.     }
  3176. #endif
  3177.   }
  3178.   return html;  
  3179. }
  3180.  
  3181. // error (404,500..)
  3182. HTS_INLINE int ishttperror(int err) {
  3183.   switch (err/100) {
  3184.     case 4: case 5: return 1;
  3185.       break;
  3186.   }
  3187.   return 0;
  3188. }
  3189.  
  3190.  
  3191. // retourne le pointeur ou le pointeur + offset si il existe dans la chaine un @ signifiant 
  3192. // une identification
  3193. HTSEXT_API char* jump_identification(const char* source) {
  3194.   const char *a,*trytofind;
  3195.   if (strcmp(source, "file://") == 0)
  3196.       return (char*) source;
  3197.   // rechercher dernier @ (car parfois email transmise dans adresse!)
  3198.   // mais sauter ftp:// Θventuel
  3199.   a = jump_protocol(source);
  3200.   trytofind = strrchr_limit(a, '@', strchr(a,'/'));
  3201.   return (char*) ( (trytofind != NULL) ? trytofind : a );
  3202. }
  3203.  
  3204. HTSEXT_API char* jump_normalized(const char* source) {
  3205.   if (strcmp(source, "file://") == 0)
  3206.       return (char*) source;
  3207.   source = jump_identification(source); 
  3208.   if (strfield(source, "www") && source[3] != '\0') {
  3209.     if (source[3] == '.') {       // www.foo.com -> foo.com
  3210.       source += 4;  
  3211.     } else {                      // www-4.foo.com -> foo.com
  3212.       const char* a = source + 3;
  3213.       while(*a && ( isdigit(*a) || *a == '-') ) a++;
  3214.       if (*a == '.') {
  3215.         source = a + 1;
  3216.       }
  3217.     }
  3218.   }
  3219.   return (char*) source;  
  3220. }
  3221.  
  3222. static int sortNormFnc(const void * a_, const void * b_) {
  3223.   char** a = (char**) a_;
  3224.   char** b = (char**) b_;
  3225.   return strcmp(*a+1, *b+1);
  3226. }
  3227.  
  3228.  
  3229. HTSEXT_API char* fil_normalized(const char* source, char* dest) {
  3230.   char lastc = 0;
  3231.   int gotquery=0;
  3232.   int ampargs=0;
  3233.   int i,j;
  3234.   char* query=NULL;
  3235.   for(i=j=0 ; source[i] != '\0'; i++) {
  3236.     if (!gotquery && source[i] == '?')
  3237.       gotquery=ampargs=1;
  3238.     if ( 
  3239.       (!gotquery && lastc == '/' && source[i] == '/')  // foo//bar -> foo/bar
  3240.       ) {
  3241.     }
  3242.     else {
  3243.       if (gotquery && source[i] == '&') {
  3244.         ampargs++;
  3245.       }
  3246.       dest[j++] = source[i];
  3247.     }
  3248.     lastc = source[i];
  3249.   }
  3250.   dest[j++] = '\0';
  3251.  
  3252.   /* Sort arguments (&foo=1&bar=2 == &bar=2&foo=1) */
  3253.   if (ampargs > 1) {
  3254.     char** amps = malloct(ampargs * sizeof(char*));
  3255.     char* copyBuff = NULL;
  3256.     int qLen=0;
  3257.     assertf(amps != NULL);
  3258.     gotquery = 0;
  3259.     for(i=j=0 ; dest[i] != '\0'; i++) {
  3260.       if ( (gotquery && dest[i] == '&') || ( !gotquery && dest[i] == '?') ) {
  3261.         if (!gotquery) {
  3262.           gotquery=1;
  3263.           query = &dest[i];
  3264.           qLen = (int)strlen(query);
  3265.         }
  3266.         assertf(j < ampargs);
  3267.         amps[j++] = &dest[i];
  3268.         dest[i] = '\0';
  3269.       }
  3270.     }
  3271.     assertf(j == ampargs);
  3272.  
  3273.     /* Sort 'em all */
  3274.     qsort(amps, ampargs, sizeof(char*), sortNormFnc);
  3275.  
  3276.     /* Replace query by sorted query */
  3277.     copyBuff = malloct(qLen + 1);
  3278.     assertf(copyBuff != NULL);
  3279.     copyBuff[0] = '\0';
  3280.     for(i = 0 ; i < ampargs ; i++) {
  3281.       if (i == 0)
  3282.         strcatbuff(copyBuff, "?");
  3283.       else
  3284.         strcatbuff(copyBuff, "&");
  3285.       strcatbuff(copyBuff, amps[i] + 1);
  3286.     }
  3287.     assert((int)strlen(copyBuff) <= qLen);
  3288.     strcpybuff(query, copyBuff);
  3289.  
  3290.     /* Cleanup */
  3291.     freet(amps);
  3292.     freet(copyBuff);
  3293.   }
  3294.   
  3295.   return dest;
  3296. }
  3297.  
  3298. #define endwith(a) ( (len >= (sizeof(a)-1)) ? ( strncmp(dest, a+len-(sizeof(a)-1), sizeof(a)-1) == 0 ) : 0 );
  3299. HTSEXT_API char* adr_normalized(const char* source, char* dest) {
  3300.   /* not yet too aggressive (no com<->net<->org checkings) */
  3301.   strcpybuff(dest, jump_normalized(source));
  3302.   return dest;
  3303. }
  3304. #undef endwith
  3305.  
  3306.  
  3307. // find port (:80) or NULL if not found
  3308. // can handle IPV6 addresses
  3309. HTSEXT_API char* jump_toport(const char* source) {
  3310.   const char *a,*trytofind;
  3311.   a = jump_identification(source);
  3312.   trytofind = strrchr_limit(a, ']', strchr(source, '/'));    // find last ] (http://[3ffe:b80:1234::1]:80/foo.html)
  3313.   a = strchr( (trytofind)?trytofind:a, ':');
  3314.   return (char*)a;
  3315. }
  3316.  
  3317. // strrchr, but not too far
  3318. char* strrchr_limit(const char* s, char c, const char* limit) {
  3319.   if (limit == NULL) {
  3320.     const char* p = strrchr(s, c);
  3321.     return (char*) ( p ? (p+1) : NULL );
  3322.   } else {
  3323.     const char *a = NULL, *p;
  3324.     for(;;) {
  3325.       p = strchr( (a) ? a : s, c);
  3326.       if ((p >= limit) || (p == NULL))
  3327.         return (char*) a;
  3328.       a=p+1;
  3329.     }
  3330.   }
  3331. }
  3332.  
  3333. // strrchr, but not too far
  3334. char* strstr_limit(const char* s, const char* sub, const char* limit) {
  3335.   if (limit == NULL) {
  3336.     return strstr(s, sub);
  3337.   } else {
  3338.     const char* pos = strstr(s, sub);
  3339.     if (pos != NULL) {
  3340.       const char* farpos = strstr(s, limit);
  3341.       if (farpos == NULL || pos < farpos)
  3342.         return (char*) pos;
  3343.     }
  3344.   }
  3345.   return NULL;
  3346. }
  3347.  
  3348. // retourner adr sans ftp://
  3349. HTS_INLINE char* jump_protocol(const char* source) {
  3350.   int p;
  3351.   // scheme
  3352.   // "Comparisons of scheme names MUST be case-insensitive" (RFC2616)
  3353.   if ((p=strfield(source,"http:")))
  3354.     source+=p;
  3355.   else if ((p=strfield(source,"ftp:")))
  3356.     source+=p;
  3357.   else if ((p=strfield(source,"https:")))
  3358.     source+=p;
  3359.   else if ((p=strfield(source,"file:")))
  3360.     source+=p;
  3361. #if HTS_USEMMS
  3362.   else if ((p=strfield(source,"mms:")))
  3363.     source+=p;
  3364. #endif
  3365.   // net_path
  3366.   if (strncmp(source,"//",2)==0)
  3367.     source+=2;
  3368.   return (char*) source;
  3369. }
  3370.  
  3371. // codage base 64 a vers b
  3372. void code64(unsigned char* a,int size_a,unsigned char* b,int crlf) {
  3373.   int i1=0,i2=0,i3=0,i4=0;
  3374.   int loop=0;
  3375.   unsigned long int store;
  3376.   int n;
  3377.   const char _hts_base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  3378.   while(size_a-- > 0) {  
  3379.     // 24 bits
  3380.     n=1; 
  3381.     store = *a++;
  3382.     if (size_a-- > 0) { n=2; store <<= 8; store |= *a++; }
  3383.     if (size_a-- > 0) { n=3; store <<= 8; store |= *a++; }
  3384.     if (n==3) {
  3385.       i4=store & 63;
  3386.       i3=(store>>6) & 63;
  3387.       i2=(store>>12) & 63;
  3388.       i1=(store>>18) & 63;
  3389.     } else if (n==2) {
  3390.       store<<=2;    
  3391.       i3=store & 63;
  3392.       i2=(store>>6) & 63;
  3393.       i1=(store>>12) & 63;
  3394.     } else {
  3395.       store<<=4;
  3396.       i2=store & 63;
  3397.       i1=(store>>6) & 63;
  3398.     }
  3399.     
  3400.     *b++ = _hts_base64[i1];
  3401.     *b++ = _hts_base64[i2];
  3402.     if (n>=2)
  3403.       *b++ = _hts_base64[i3];
  3404.     else
  3405.       *b++ = '=';
  3406.     if (n>=3)
  3407.       *b++ = _hts_base64[i4];
  3408.     else
  3409.       *b++ = '=';
  3410.  
  3411.     if (crlf && ( ( loop += 3 ) % 60) == 0 ) {
  3412.       *b++ = '\r';
  3413.       *b++ = '\n';
  3414.     }
  3415.   }
  3416.   *b++='\0';
  3417. }
  3418.  
  3419. // remplacer " par " etc..
  3420. // buffer MAX 1Ko
  3421. #define strcmpbeg(a, b) strncmp(a, b, strlen(b))
  3422. HTSEXT_API void unescape_amp(char* s) {
  3423.   while(*s) {
  3424.     if (*s=='&') {
  3425.       char* end=strchr(s,';');
  3426.       if ( end && (((int) (end - s)) <= 8) ) {
  3427.         unsigned char c=0;
  3428.         
  3429.         // http://www.w3.org/TR/xhtml-modularization/dtd_module_defs.html
  3430.         if (strcmpbeg(s, "&#") == 0) {
  3431.           int num=0;
  3432.           if ( (s[2] == 'x') || (s[2] == 'X')) {
  3433.             if (sscanf(s+3, "%x", &num) == 1 && num <= 0xff) {
  3434.               c=(unsigned char) num;
  3435.             }
  3436.           } else {
  3437.             if (sscanf(s+2, "%d", &num) == 1 && num <= 0xff) {
  3438.               c=(unsigned char) num;
  3439.             }
  3440.           }
  3441.         }
  3442.         else if (strcmpbeg(s, " ")==0)
  3443.           c=32; // hack - c=160;
  3444.         else if (strcmpbeg(s, "¡")==0)
  3445.           c=161;
  3446.         else if (strcmpbeg(s, "¢")==0)
  3447.           c=162;
  3448.         else if (strcmpbeg(s, "£")==0)
  3449.           c=163;
  3450.         else if (strcmpbeg(s, "¤")==0)
  3451.           c=164;
  3452.         else if (strcmpbeg(s, "¥")==0)
  3453.           c=165;
  3454.         else if (strcmpbeg(s, "¦")==0)
  3455.           c=166;
  3456.         else if (strcmpbeg(s, "§")==0)
  3457.           c=167;
  3458.         else if (strcmpbeg(s, "¨")==0)
  3459.           c=168;
  3460.         else if (strcmpbeg(s, "©")==0)
  3461.           c=169;
  3462.         else if (strcmpbeg(s, "ª")==0)
  3463.           c=170;
  3464.         //else if (strcmpbeg(s, "«")==0)
  3465.         //  c=171;
  3466.         else if (strcmpbeg(s, "¬")==0)
  3467.           c=172;
  3468.         //else if (strcmpbeg(s, "­")==0)
  3469.         //  c=173;
  3470.         else if (strcmpbeg(s, "®")==0)
  3471.           c=174;
  3472.         else if (strcmpbeg(s, "¯")==0)
  3473.           c=175;
  3474.         else if (strcmpbeg(s, "°")==0)
  3475.           c=176;
  3476.         else if (strcmpbeg(s, "±")==0)
  3477.           c=177;
  3478.         else if (strcmpbeg(s, "²")==0)
  3479.           c=178;
  3480.         else if (strcmpbeg(s, "³")==0)
  3481.           c=179;
  3482.         else if (strcmpbeg(s, "´")==0)
  3483.           c=180;
  3484.         else if (strcmpbeg(s, "µ")==0)
  3485.           c=181;
  3486.         else if (strcmpbeg(s, "¶")==0)
  3487.           c=182;
  3488.         else if (strcmpbeg(s, "·")==0)
  3489.           c=183;
  3490.         else if (strcmpbeg(s, "¸")==0)
  3491.           c=184;
  3492.         else if (strcmpbeg(s, "¹")==0)
  3493.           c=185;
  3494.         else if (strcmpbeg(s, "º")==0)
  3495.           c=186;
  3496.         //else if (strcmpbeg(s, "»")==0)
  3497.         //  c=187;
  3498.         else if (strcmpbeg(s, "¼")==0)
  3499.           c=188;
  3500.         else if (strcmpbeg(s, "½")==0)
  3501.           c=189;
  3502.         else if (strcmpbeg(s, "¾")==0)
  3503.           c=190;
  3504.         else if (strcmpbeg(s, "¿")==0)
  3505.           c=191;
  3506.         else if (strcmpbeg(s, "À")==0)
  3507.           c=192;
  3508.         else if (strcmpbeg(s, "Á")==0)
  3509.           c=193;
  3510.         else if (strcmpbeg(s, "Â")==0)
  3511.           c=194;
  3512.         else if (strcmpbeg(s, "Ã")==0)
  3513.           c=195;
  3514.         else if (strcmpbeg(s, "Ä")==0)
  3515.           c=196;
  3516.         else if (strcmpbeg(s, "Å")==0)
  3517.           c=197;
  3518.         else if (strcmpbeg(s, "Æ")==0)
  3519.           c=198;
  3520.         else if (strcmpbeg(s, "Ç")==0)
  3521.           c=199;
  3522.         else if (strcmpbeg(s, "È")==0)
  3523.           c=200;
  3524.         else if (strcmpbeg(s, "É")==0)
  3525.           c=201;
  3526.         else if (strcmpbeg(s, "Ê")==0)
  3527.           c=202;
  3528.         else if (strcmpbeg(s, "Ë")==0)
  3529.           c=203;
  3530.         else if (strcmpbeg(s, "Ì")==0)
  3531.           c=204;
  3532.         else if (strcmpbeg(s, "Í")==0)
  3533.           c=205;
  3534.         else if (strcmpbeg(s, "Î")==0)
  3535.           c=206;
  3536.         else if (strcmpbeg(s, "Ï")==0)
  3537.           c=207;
  3538.         else if (strcmpbeg(s, "Ð")==0)
  3539.           c=208;
  3540.         else if (strcmpbeg(s, "Ñ")==0)
  3541.           c=209;
  3542.         else if (strcmpbeg(s, "Ò")==0)
  3543.           c=210;
  3544.         else if (strcmpbeg(s, "Ó")==0)
  3545.           c=211;
  3546.         else if (strcmpbeg(s, "Ô")==0)
  3547.           c=212;
  3548.         else if (strcmpbeg(s, "Õ")==0)
  3549.           c=213;
  3550.         else if (strcmpbeg(s, "Ö")==0)
  3551.           c=214;
  3552.         else if (strcmpbeg(s, "×")==0)
  3553.           c=215;
  3554.         else if (strcmpbeg(s, "Ø")==0)
  3555.           c=216;
  3556.         else if (strcmpbeg(s, "Ù")==0)
  3557.           c=217;
  3558.         else if (strcmpbeg(s, "Ú")==0)
  3559.           c=218;
  3560.         else if (strcmpbeg(s, "Û")==0)
  3561.           c=219;
  3562.         else if (strcmpbeg(s, "Ü")==0)
  3563.           c=220;
  3564.         else if (strcmpbeg(s, "Ý")==0)
  3565.           c=221;
  3566.         else if (strcmpbeg(s, "Þ")==0)
  3567.           c=222;
  3568.         else if (strcmpbeg(s, "ß")==0)
  3569.           c=223;
  3570.         else if (strcmpbeg(s, "à")==0)
  3571.           c=224;
  3572.         else if (strcmpbeg(s, "á")==0)
  3573.           c=225;
  3574.         else if (strcmpbeg(s, "â")==0)
  3575.           c=226;
  3576.         else if (strcmpbeg(s, "ã")==0)
  3577.           c=227;
  3578.         else if (strcmpbeg(s, "ä")==0)
  3579.           c=228;
  3580.         else if (strcmpbeg(s, "å")==0)
  3581.           c=229;
  3582.         else if (strcmpbeg(s, "æ")==0)
  3583.           c=230;
  3584.         else if (strcmpbeg(s, "ç")==0)
  3585.           c=231;
  3586.         else if (strcmpbeg(s, "è")==0)
  3587.           c=232;
  3588.         else if (strcmpbeg(s, "é")==0)
  3589.           c=233;
  3590.         else if (strcmpbeg(s, "ê")==0)
  3591.           c=234;
  3592.         else if (strcmpbeg(s, "ë")==0)
  3593.           c=235;
  3594.         else if (strcmpbeg(s, "ì")==0)
  3595.           c=236;
  3596.         else if (strcmpbeg(s, "í")==0)
  3597.           c=237;
  3598.         else if (strcmpbeg(s, "î")==0)
  3599.           c=238;
  3600.         else if (strcmpbeg(s, "ï")==0)
  3601.           c=239;
  3602.         else if (strcmpbeg(s, "ð")==0)
  3603.           c=240;
  3604.         else if (strcmpbeg(s, "ñ")==0)
  3605.           c=241;
  3606.         else if (strcmpbeg(s, "ò")==0)
  3607.           c=242;
  3608.         else if (strcmpbeg(s, "ó")==0)
  3609.           c=243;
  3610.         else if (strcmpbeg(s, "ô")==0)
  3611.           c=244;
  3612.         else if (strcmpbeg(s, "õ")==0)
  3613.           c=245;
  3614.         else if (strcmpbeg(s, "ö")==0)
  3615.           c=246;
  3616.         else if (strcmpbeg(s, "÷")==0)
  3617.           c=247;
  3618.         else if (strcmpbeg(s, "ø")==0)
  3619.           c=248;
  3620.         else if (strcmpbeg(s, "ù")==0)
  3621.           c=249;
  3622.         else if (strcmpbeg(s, "ú")==0)
  3623.           c=250;
  3624.         else if (strcmpbeg(s, "û")==0)
  3625.           c=251;
  3626.         else if (strcmpbeg(s, "ü")==0)
  3627.           c=252;
  3628.         else if (strcmpbeg(s, "ý")==0)
  3629.           c=253;
  3630.         else if (strcmpbeg(s, "þ")==0)
  3631.           c=254;
  3632.         else if (strcmpbeg(s, "ÿ")==0)
  3633.           c=255;
  3634.         //        
  3635.         else if (strcmpbeg(s,"&")==0)
  3636.           c='&';
  3637.         else if (strcmpbeg(s,">")==0)
  3638.           c='>';
  3639.         else if (strcmpbeg(s,"«")==0)
  3640.           c='\"';
  3641.         else if (strcmpbeg(s,"<")==0)
  3642.           c='<';
  3643.         else if (strcmpbeg(s," ")==0)
  3644.           c=' ';
  3645.         else if (strcmpbeg(s,""")==0)
  3646.           c='\"';
  3647.         else if (strcmpbeg(s,"»")==0)
  3648.           c='\"';
  3649.         else if (strcmpbeg(s,"­")==0)
  3650.           c='-';
  3651.         else if (strcmpbeg(s,"˜")==0)
  3652.           c='~';
  3653.         // remplacer?
  3654.         if (c) {
  3655.           char BIGSTK buff[HTS_URLMAXSIZE*2];
  3656.           buff[0]=(char) c;
  3657.           strcpybuff(buff+1,end+1);
  3658.           strcpybuff(s,buff);
  3659.         }
  3660.       }
  3661.     }
  3662.     s++;
  3663.   }
  3664. }
  3665.  
  3666. static int ehexh(char c) {
  3667.   if ((c>='0') && (c<='9')) return c-'0';
  3668.   if ((c>='a') && (c<='f')) c-=('a'-'A');
  3669.   if ((c>='A') && (c<='F')) return (c-'A'+10);
  3670.   return 0;
  3671. }
  3672.  
  3673. static int ehex(const char* s) {
  3674.   return 16*ehexh(*s)+ehexh(*(s+1));
  3675. }
  3676.  
  3677. // remplacer %20 par ' ', | par : etc..
  3678. // buffer MAX 1Ko
  3679. HTSEXT_API char* unescape_http(char *catbuff, const char* s) {
  3680.   int i,j=0;
  3681.   for (i=0;i<(int) strlen(s);i++) {
  3682.     if (s[i]=='%') {
  3683.       i++;
  3684.       catbuff[j++]=(char) ehex(s+i);
  3685.       i++;    // sauter 2 caractΦres finalement
  3686.     }
  3687.     /*
  3688.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  3689.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  3690.       tempo[j++]=':';
  3691.     }
  3692.     */
  3693.     else
  3694.       catbuff[j++]=s[i];
  3695.   }
  3696.   catbuff[j++]='\0';
  3697.   return catbuff;
  3698. }
  3699.  
  3700. // unescape in URL/URI ONLY what has to be escaped, to form a standard URL/URI
  3701. // DOES NOT DECODE %25
  3702. HTSEXT_API char* unescape_http_unharm(char *catbuff, const char* s, int no_high) {
  3703.   int i,j=0;
  3704.   for (i=0;i<(int) strlen(s);i++) {
  3705.     if (s[i]=='%') {
  3706.       int nchar=(char) ehex(s+i+1);
  3707.  
  3708.       int test = (  CHAR_RESERVED(nchar)
  3709.                 || ( nchar != '%' && CHAR_DELIM(nchar) )
  3710.                 || CHAR_UNWISE(nchar)
  3711.                 || CHAR_LOW(nchar)        /* CHAR_SPECIAL */
  3712.                 || CHAR_XXAVOID(nchar) 
  3713.                 || (
  3714.                   (no_high)
  3715.                   &&
  3716.                   CHAR_HIG(nchar)
  3717.                 )
  3718.                 );
  3719.  
  3720.       if (!test) {
  3721.         catbuff[j++]=(char) ehex(s+i+1);
  3722.         i+=2;
  3723.       } else {
  3724.         catbuff[j++]='%';
  3725.       }
  3726.     }
  3727.     /*
  3728.     NON a cause de trucs comme /home/0,1837,1|7|1173|Content,00.html
  3729.     else if (s[i]=='|') {                     // exemple: file:///C|Program%20Files...
  3730.       tempo[j++]=':';
  3731.     }
  3732.     */
  3733.     else
  3734.       catbuff[j++]=s[i];
  3735.   }
  3736.   catbuff[j++]='\0';
  3737.   return catbuff;
  3738. }
  3739.  
  3740. // remplacer " par %xx etc..
  3741. // buffer MAX 1Ko
  3742. HTSEXT_API void escape_spc_url(char* s) {
  3743.   x_escape_http(s,2);
  3744. }
  3745. // smith / john -> smith%20%2f%20john
  3746. HTSEXT_API void escape_in_url(char* s) {
  3747.   x_escape_http(s,1);
  3748. }
  3749. // smith / john -> smith%20/%20john
  3750. HTSEXT_API void escape_uri(char* s) {
  3751.   x_escape_http(s,3);
  3752. }
  3753. HTSEXT_API void escape_uri_utf(char* s) {
  3754.   x_escape_http(s,30);
  3755. }
  3756. HTSEXT_API void escape_check_url(char* s) {
  3757.   x_escape_http(s,0);
  3758. }
  3759. // same as escape_check_url, but returns char*
  3760. HTSEXT_API char* escape_check_url_addr(char *catbuff, const char* s) {
  3761.   char* adr;
  3762.   escape_check_url(adr = concat(catbuff, s, ""));
  3763.   return adr;
  3764. }
  3765.  
  3766. // strip all control characters
  3767. HTSEXT_API void escape_remove_control(char* s) {
  3768.   unsigned char* ss = (unsigned char*) s;
  3769.   while(*ss) {
  3770.     if (*ss < 32) {    /* CONTROL characters go away! */
  3771.       char BIGSTK tmp[HTS_URLMAXSIZE*2];
  3772.       strcpybuff(tmp, ss+1);
  3773.       strcpybuff(ss, tmp);
  3774.     } else {
  3775.       ss++;
  3776.     }
  3777.   }
  3778. }
  3779.  
  3780. HTSEXT_API void x_escape_html(char* s) {
  3781.   while(*s) {
  3782.     int test=0;
  3783.       test = (
  3784.                 CHAR_HIG(*s)
  3785.              || CHAR_XXAVOID(*s) );
  3786.  
  3787.     if (test) {
  3788.       char BIGSTK buffer[HTS_URLMAXSIZE*3];
  3789.       int n;
  3790.       n = (int)(unsigned char) *s;
  3791.       strcpybuff(buffer, s+1);
  3792.       sprintf(s,"&#x%02x;", n);
  3793.       strcatbuff(s, buffer);
  3794.     }
  3795.     s++;
  3796.   }
  3797. }
  3798.  
  3799.  
  3800. HTSEXT_API void x_escape_http(char* s,int mode) {
  3801.   while(*s) {
  3802.     int test=0;
  3803.     if (mode == 0)
  3804.       test=(strchr("\" ",*s)!=0);
  3805.     else if (mode==1) {
  3806.       test = (  CHAR_RESERVED(*s)
  3807.              || CHAR_DELIM(*s)
  3808.              || CHAR_UNWISE(*s)
  3809.              || CHAR_SPECIAL(*s)
  3810.              || CHAR_XXAVOID(*s)
  3811.              || CHAR_MARK(*s));
  3812.     }
  3813.     else if (mode==2)
  3814.       test=(*s == ' ');           // n'escaper que espace
  3815.     else if (mode==3) {                   // Θchapper que ce qui est nΘcessaire
  3816.       test = (
  3817.                 CHAR_SPECIAL(*s)
  3818.              || CHAR_XXAVOID(*s) );
  3819.     }
  3820.     else if (mode==30) {                   // Θchapper que ce qui est nΘcessaire
  3821.       test = (
  3822.                 CHAR_LOW(*s)
  3823.              || CHAR_XXAVOID(*s) );
  3824.     }
  3825.  
  3826.     if (test) {
  3827.       char BIGSTK buffer[HTS_URLMAXSIZE*3];
  3828.       int n;
  3829.       n=(int)(unsigned char) *s;
  3830.       strcpybuff(buffer,s+1);
  3831.       sprintf(s,"%%%02x",n);
  3832.       strcatbuff(s,buffer);
  3833.     }
  3834.     s++;
  3835.   }
  3836. }
  3837.  
  3838. HTSEXT_API void escape_for_html_print(char* s, char* d) {
  3839.   for( ; *s ; s++) {
  3840.     if (*s == '&') {
  3841.       strcpybuff(d, "&");
  3842.       d += strlen(d);
  3843.     } else {
  3844.       *d++ = *s;
  3845.     }
  3846.   }
  3847.   *d = '\0';
  3848. }
  3849.  
  3850. HTSEXT_API void escape_for_html_print_full(char* s, char* d) {
  3851.   for( ; *s ; s++) {
  3852.     if (*s == '&') {
  3853.       strcpybuff(d, "&");
  3854.       d += strlen(d);
  3855.     } else if (CHAR_HIG(*s)) {
  3856.       sprintf(d, "&#x%02x;", (unsigned char) *s);
  3857.       d += strlen(d);
  3858.     } else {
  3859.       *d++ = *s;
  3860.     }
  3861.   }
  3862.   *d = '\0';
  3863. }
  3864.  
  3865. // concat, concatΦne deux chaines et renvoi le rΘsultat
  3866. // permet d'allΘger grandement le code
  3867. // il faut savoir qu'on ne peut mettre plus de 16 concat() dans une expression
  3868. HTSEXT_API char* concat(char *catbuff,const char* a,const char* b) {
  3869.     if (a != NULL && a[0] != '\0') {
  3870.         strcpybuff(catbuff, a);
  3871.     } else {
  3872.         catbuff[0] = '\0';
  3873.     }
  3874.     if (b != NULL && b[0] != '\0') {
  3875.         strcatbuff(catbuff, b);
  3876.     }
  3877.   return catbuff;
  3878. }
  3879. // conversion fichier / -> antislash
  3880. static char* __fconv(char* a) {
  3881. #if HTS_DOSNAME
  3882.   int i;
  3883.   for(i = 0 ; a[i] != 0 ; i++)
  3884.     if (a[i] == '/')  // Unix-to-DOS style
  3885.       a[i] = '\\';
  3886. #endif
  3887.   return a;
  3888. }
  3889.  
  3890. HTSEXT_API char* fconcat(char *catbuff, const char* a, const char* b) {
  3891.   return __fconv(concat(catbuff,a,b));
  3892. }
  3893. HTSEXT_API char* fconv(char *catbuff, const char* a) {
  3894.   return __fconv(concat(catbuff,a,""));
  3895. }
  3896.  
  3897. /* / et \\ en / */
  3898. static char* __fslash(char* a) {
  3899.   int i;
  3900.   for(i = 0 ; a[i] != 0 ; i++)
  3901.     if (a[i] == '\\')  // convertir
  3902.       a[i] = '/';
  3903.   return a;
  3904. }
  3905. char* fslash(char *catbuff, const char* a) {
  3906.   return __fslash(concat(catbuff,a,NULL));
  3907. }
  3908.  
  3909. // conversion minuscules, avec buffer
  3910. char* convtolower(char *catbuff, const char* a) {
  3911.   strcpybuff(catbuff,a);
  3912.   hts_lowcase(catbuff);  // lower case
  3913.   return catbuff;
  3914. }
  3915.  
  3916. // conversion en minuscules
  3917. void hts_lowcase(char* s) {
  3918.   int i;
  3919.   for(i=0;i<(int) strlen(s);i++)
  3920.     if ((s[i]>='A') && (s[i]<='Z'))
  3921.       s[i]+=('a'-'A');
  3922. }
  3923.  
  3924. // remplacer un caractΦre d'une chaεne dans une autre
  3925. HTS_INLINE void hts_replace(char *s,char from,char to) { 
  3926.   char* a;
  3927.   while ((a=strchr(s,from))!=NULL) {
  3928.     *a=to;
  3929.   }
  3930. }
  3931.  
  3932.  
  3933. // caractΦre espace, guillemets, CR, LF etc..
  3934. /* SECTION OPTIMISEE:
  3935.   #define  is_space(c) (strchr(" \"\x0d\x0a\x09'",c)!=NULL)
  3936.   #define  is_realspace(c) (strchr(" \x0d\x0a\x09\x0c",c)!=NULL)
  3937. */
  3938. /*
  3939. HTS_INLINE int is_space(char c) {
  3940.   if (c==' ')  return 1;  // spc
  3941.   if (c=='"')  return 1;  // quote
  3942.   if (c==10)   return 1;  // lf
  3943.   if (c==13)   return 1;  // cr
  3944.   if (c=='\'') return 1;  // quote
  3945.   //if (c=='`')  return 1;  // backquote      << non
  3946.   if (c==9)    return 1;  // tab
  3947.   return 0;
  3948. }
  3949. */
  3950.  
  3951. // caractΦre espace, CR, LF, TAB
  3952. /*
  3953. HTS_INLINE int is_realspace(char c) {
  3954.   if (c==' ')  return 1;  // spc
  3955.   if (c==10)   return 1;  // lf
  3956.   if (c==13)   return 1;  // cr
  3957.   if (c==9)    return 1;  // tab
  3958.   return 0;
  3959. }
  3960. */
  3961.  
  3962.  
  3963.  
  3964.  
  3965.  
  3966. // deviner type d'un fichier local..
  3967. // ex: fil="toto.gif" -> s="image/gif"
  3968. void guess_httptype(httrackp *opt,char *s,const char *fil) {
  3969.   get_httptype(opt,s, fil, 1);
  3970. }
  3971. // idem
  3972. // flag: 1 si toujours renvoyer un type
  3973. HTSEXT_API void get_httptype(httrackp *opt,char *s,const char *fil,int flag) {
  3974.   // userdef overrides get_httptype
  3975.   if (get_userhttptype(opt, s, fil)) {
  3976.     return ;
  3977.   }
  3978.   // regular tests
  3979.   if (ishtml(opt,fil) == 1) {
  3980.     strcpybuff(s,"text/html");
  3981.   } else {
  3982.     /* Check html -> text/html */
  3983.     const char* a = fil + strlen(fil) - 1;    
  3984.     while ( (*a!='.') && (*a!='/') && (a>fil)) a--;
  3985.     if (*a=='.' && strlen(a) < 32) {
  3986.       int j=0;
  3987.       a++;
  3988.       while(strnotempty(hts_mime[j][1])) {
  3989.         if (strfield2(hts_mime[j][1],a)) {
  3990.           if (hts_mime[j][0][0]!='*') {    // Une correspondance existe
  3991.             strcpybuff(s,hts_mime[j][0]);
  3992.             return;
  3993.           }
  3994.         }
  3995.         j++;
  3996.       }
  3997.       
  3998.       if (flag)
  3999.         sprintf(s,"application/%s",a);
  4000.     } else {
  4001.       if (flag)
  4002.         strcpybuff(s,"application/octet-stream");
  4003.     }
  4004.   }
  4005. }
  4006.  
  4007. // get type of fil (php)
  4008. // s: buffer (text/html) or NULL
  4009. // return: 1 if known by user
  4010. int get_userhttptype(httrackp *opt, char *s, const char *fil) {
  4011.   if (s != NULL) {
  4012.     if (s)
  4013.       s[0]='\0';
  4014.     if (fil == NULL || *fil == '\0')
  4015.       return 0;
  4016. #if 1
  4017.     if (StringLength(opt->mimedefs) > 0) {
  4018.  
  4019.       /* Check --assume foooo/foo/bar.cgi=text/html, then foo/bar.cgi=text/html, then bar.cgi=text/html */
  4020.       /* also: --assume baz,bar,foooo/foo/bar.cgi=text/html */
  4021.       /* start from path begining */
  4022.       do {
  4023.         const char* next;
  4024.         const char* mimedefs = StringBuff(opt->mimedefs);    /* loop through mime definitions : \nfoo=bar\nzoo=baz\n.. */
  4025.         while(*mimedefs != '\0') {
  4026.           const char* segment = fil + 1;
  4027.           if (*mimedefs == '\n') {
  4028.             mimedefs++;
  4029.           }
  4030.           /* compare current segment with user's definition */
  4031.           do {
  4032.             int i;
  4033.             /* check current item */
  4034.             for(i = 0 ; 
  4035.               mimedefs[i] != '\0'           /* end of all defs */
  4036.               && mimedefs[i] != ' '         /* next item in left list */
  4037.               && mimedefs[i] != '='         /* end of left list */
  4038.               && mimedefs[i] != '\n'        /* end of this def (?) */
  4039.               && mimedefs[i] == segment[i]  /* same item */
  4040.               ; i++);
  4041.             /* success */
  4042.             if ( ( mimedefs[i] == '=' || mimedefs[i] == ' ' ) && segment[i] == '\0') {
  4043.               int i2;
  4044.               while(mimedefs[i] != 0 && mimedefs[i] != '\n' && mimedefs[i] != '=') i++;
  4045.               if (mimedefs[i] == '=') {
  4046.                 i++;
  4047.                 for(i2 = 0 ; mimedefs[i + i2] != '\n' && mimedefs[i + i2] != '\0' ; i2++) {
  4048.                   s[i2] = mimedefs[i + i2];
  4049.                 }
  4050.                 s[i2] = '\0';
  4051.                 return 1;   /* SUCCESS! */
  4052.               }
  4053.             }
  4054.             /* next item in list */
  4055.             for(mimedefs += i ; 
  4056.               *mimedefs != '\0' && *mimedefs != '\n' && *mimedefs != '=' && *mimedefs != ' ' ; 
  4057.               mimedefs++);
  4058.             if (*mimedefs == ' ') {
  4059.               mimedefs++;
  4060.             }
  4061.           } while(*mimedefs != '\0' && *mimedefs != '\n' && *mimedefs != '=');
  4062.           /* next user-def */
  4063.           for( ; *mimedefs != '\0' && *mimedefs != '\n' ; mimedefs++);
  4064.         }
  4065.         /* shorten segment */
  4066.         next = strchr(fil + 1, '/');
  4067.         if (next == NULL) {
  4068.           /* ext tests */
  4069.           next = strchr(fil + 1, '.');
  4070.         }
  4071.         fil = next;
  4072.       } while(fil != NULL);
  4073.     }
  4074. #else
  4075.     if (*buffer) {
  4076.       char BIGSTK search[1024];
  4077.       char* detect;
  4078.  
  4079.  
  4080.       sprintf(search,"\n%s=",ext);    // php=text/html
  4081.       detect=strstr(*buffer,search);
  4082.       if (!detect) {
  4083.         sprintf(search,"\n%s\n",ext); // php\ncgi=text/html
  4084.         detect=strstr(*buffer,search);
  4085.       }
  4086.       if (detect) {
  4087.         detect=strchr(detect,'=');
  4088.         if (detect) {
  4089.           detect++;
  4090.           if (s) {
  4091.             char* a;
  4092.             a=strchr(detect,'\n');
  4093.             if (a) {
  4094.               strncatbuff(s,detect,(int) (a - detect));
  4095.             }
  4096.           }
  4097.           return 1;
  4098.         }
  4099.       }
  4100.     }
  4101. #endif
  4102.   }
  4103.   return 0;
  4104. }
  4105. // renvoyer extesion d'un type mime..
  4106. // ex: "image/gif" -> gif
  4107. void give_mimext(char *s,const char *st) {   
  4108.   int ok=0;
  4109.   int j=0;
  4110.   s[0]='\0';
  4111.   while( (!ok) && (strnotempty(hts_mime[j][1])) ) {
  4112.     if (strfield2(hts_mime[j][0],st)) {
  4113.       if (hts_mime[j][1][0]!='*') {    // Une correspondance existe
  4114.         strcpybuff(s,hts_mime[j][1]);
  4115.         ok=1;
  4116.       }
  4117.     }
  4118.     j++;
  4119.   }
  4120.   // wrap "x" mimetypes, such as:
  4121.   // application/x-mp3
  4122.   // or
  4123.   // application/mp3
  4124.   if (!ok) {
  4125.     int p;
  4126.     const char* a=NULL;
  4127.     if ((p=strfield(st,"application/x-")))
  4128.       a=st+p;
  4129.     else if ((p=strfield(st,"application/")))
  4130.       a=st+p;
  4131.     if (a) {
  4132.       if ((int)strlen(a) >= 1) {
  4133.         if ((int)strlen(a) <= 4) {
  4134.           strcpybuff(s,a);
  4135.           ok=1;
  4136.         }
  4137.       }
  4138.     }
  4139.   }
  4140. }
  4141. // extension connue?..
  4142. //  0 : non
  4143. //  1 : oui
  4144. //  2 : html
  4145. HTSEXT_API int is_knowntype(httrackp *opt,const char *fil) {
  4146.     char catbuff[CATBUFF_SIZE];
  4147.   const char *ext;
  4148.   int j=0;
  4149.   if (!fil)
  4150.     return 0;
  4151.   ext = get_ext(catbuff, fil);
  4152.   while(strnotempty(hts_mime[j][1])) {
  4153.     if (strfield2(hts_mime[j][1], ext)) {
  4154.       if (strfield2(hts_mime[j][0], "text/html"))
  4155.         return 2;
  4156.       else
  4157.         return 1;
  4158.     }
  4159.     j++;
  4160.   }
  4161.  
  4162.   // Known by user?
  4163.   return (is_userknowntype(opt,fil));
  4164. }
  4165. // extension : html,gif..
  4166. HTSEXT_API char* get_ext(char *catbuff, const char *fil) {
  4167.   const char *a=fil+strlen(fil)-1;    
  4168.  
  4169.   while ( (*a!='.') && (*a!='/')  && (a>fil)) a--;
  4170.   if (*a=='.') {
  4171.         char fil_noquery[HTS_URLMAXSIZE*2];
  4172.     char* b;
  4173.     fil_noquery[0]='\0';
  4174.     a++;  // pointer sur extension
  4175.     strncatbuff(fil_noquery,a,HTS_URLMAXSIZE);
  4176.     b=strchr(fil_noquery,'?');
  4177.     if (b)
  4178.       *b='\0';
  4179.     return concat(catbuff,fil_noquery,"");
  4180.   }
  4181.   else
  4182.     return "";
  4183. }
  4184. // known type?..
  4185. //  0 : no
  4186. //  1 : yes
  4187. //  2 : html
  4188. // setdefs : set mime buffer:
  4189. //   file=(char*) "asp=text/html\nphp=text/html\n"
  4190. HTSEXT_API int is_userknowntype(httrackp *opt,const char *fil) {
  4191.   char BIGSTK mime[1024];
  4192.   if (!fil)
  4193.     return 0;
  4194.   if (!strnotempty(fil))
  4195.     return 0;
  4196.   mime[0]='\0';
  4197.   get_userhttptype(opt, mime, fil);
  4198.   if (!strnotempty(mime))
  4199.     return 0;
  4200.   else if (strfield2(mime,"text/html"))
  4201.     return 2;
  4202.   else
  4203.     return 1;
  4204. }
  4205.  
  4206. // page dynamique?
  4207. // is_dyntype(get_ext("foo.asp"))
  4208. HTSEXT_API int is_dyntype(const char *fil) {
  4209.   int j=0;
  4210.   if (!fil)
  4211.     return 0;
  4212.   if (!strnotempty(fil))
  4213.     return 0;
  4214.   while(strnotempty(hts_ext_dynamic[j])) {
  4215.     if (strfield2(hts_ext_dynamic[j],fil)) {
  4216.       return 1;
  4217.     }
  4218.     j++;
  4219.   }
  4220.   return 0;
  4221. }
  4222.  
  4223. // types critiques qui ne doivent pas Ωtre changΘs car renvoyΘs par des serveurs qui ne
  4224. // connaissent pas le type
  4225. int may_unknown(httrackp *opt,const char* st) {
  4226.   int j=0;
  4227.   // types mΘdia
  4228.   if (may_be_hypertext_mime(opt,st, "")) {
  4229.     return 1;
  4230.   }
  4231.   while(strnotempty(hts_mime_keep[j])) {
  4232.     if (strfield2(hts_mime_keep[j],st)) {      // trouvΘ
  4233.       return 1;
  4234.     }
  4235.     j++;
  4236.   }    
  4237.   return 0;
  4238. }
  4239.  
  4240. /* returns 1 if the mime/filename seems to be bogus because of badly recognized multiple extension
  4241.   ; such as "application/x-wais-source" for "httrack-3.42-1.el5.src.rpm"
  4242.   reported by Hippy Dave 08/2008 (3.43) */
  4243. int may_bogus_multiple(httrackp *opt, const char* mime, const char *filename) {
  4244.   int j;
  4245.   for(j = 0 ; strnotempty(hts_mime_keep[j]) ; j++) {
  4246.     if (strfield2(hts_mime_bogus_multiple[j], mime)) {      /* found mime type in suspicious list */
  4247.       char ext[64];
  4248.       ext[0] = '\0';
  4249.       give_mimext(ext, mime);
  4250.       if (ext[0] != 0) {   /* we have an extension for that */
  4251.         const size_t ext_size = strlen(ext);
  4252.         const char *file = strrchr(filename, '/');  /* fetch terminal filename */
  4253.         if (file != NULL) {
  4254.           int i;
  4255.           for(i = 0 ; file[i] != 0 ; i++) {
  4256.             if (i > 0 && file[i - 1] == '.' && strncasecmp(&file[i], ext, ext_size) == 0 
  4257.               && ( file[i + ext_size] == 0 || file[i + ext_size] == '.' || file[i + ext_size] == '?' ) ) {
  4258.               return 1;  /* is ambiguous */
  4259.             }
  4260.           }
  4261.         }
  4262.       }
  4263.       return 0;
  4264.     }
  4265.   }    
  4266.   return 0;
  4267. }
  4268.  
  4269. /* filename extension should not be changed because potentially bogus ; replaces may_unknown() (3.43) */
  4270. int may_unknown2(httrackp *opt, const char* mime, const char *filename) {
  4271.   int ret = may_unknown(opt, mime);
  4272.   if (ret == 0) {
  4273.     ret = may_bogus_multiple(opt, mime, filename);
  4274.   }
  4275.   return ret;
  4276. }
  4277.  
  4278. // -- Utils fichiers
  4279.  
  4280. // pretty print for i/o
  4281. void fprintfio(FILE* fp,char* buff,char* prefix) {
  4282.   char nl=1;
  4283.   while(*buff) {
  4284.     switch(*buff) {
  4285.     case 13: break;
  4286.     case 10:
  4287.       fprintf(fp,"\r\n");
  4288.       nl=1;
  4289.     break;
  4290.     default:
  4291.       if (nl)
  4292.         fprintf(fp,prefix);
  4293.       nl=0;
  4294.       fputc(*buff,fp);
  4295.     }
  4296.     buff++;
  4297.   }
  4298. }
  4299.  
  4300. /* Le fichier existe-t-il? (ou est-il accessible?) */
  4301. int fexist(const char* s) {
  4302.     char catbuff[CATBUFF_SIZE];
  4303.   struct stat st;
  4304.   memset(&st, 0, sizeof(st));
  4305.   if (stat(fconv(catbuff,s), &st) == 0) {
  4306.     if (S_ISREG(st.st_mode)) {
  4307.       return 1;
  4308.     }
  4309.   }
  4310.   return 0;
  4311.  
  4312. /* Taille d'un fichier, -1 si n'existe pas */
  4313. /* fp->_cnt ne fonctionne pas sur toute les plate-formes :-(( */
  4314. /* Note: NOT YET READY FOR 64-bit */
  4315. off_t fsize(const char* s) {
  4316.     char catbuff[CATBUFF_SIZE];
  4317.     FILE* fp;
  4318.   if (strnotempty(s)==0)     // nom vide: erreur
  4319.     return -1;
  4320.   fp=fopen(fconv(catbuff,s),"rb");
  4321.   if (fp!=NULL) {
  4322.     off_t i;
  4323.     fseek(fp,0,SEEK_END);
  4324. #ifdef HTS_FSEEKO
  4325.     i=ftello(fp);
  4326. #else
  4327.     i=ftell(fp);
  4328. #endif
  4329.     fclose(fp);
  4330.     return i;
  4331.   } else
  4332.     return -1;
  4333. }
  4334.  
  4335. off_t fpsize(FILE* fp) {
  4336.   off_t oldpos,size;
  4337.   if (!fp)
  4338.     return -1;
  4339. #ifdef HTS_FSEEKO
  4340.   oldpos=ftello(fp);
  4341. #else
  4342.   oldpos=ftell(fp);
  4343. #endif
  4344.   fseek(fp,0,SEEK_END);
  4345. #ifdef HTS_FSEEKO
  4346.   size=ftello(fp);
  4347.   fseeko(fp,oldpos,SEEK_SET);
  4348. #else
  4349.   size=ftell(fp);
  4350.   fseek(fp,oldpos,SEEK_SET);
  4351. #endif
  4352.   return size;
  4353. }
  4354.  
  4355. /* root dir, with ending / */
  4356. typedef struct {
  4357.   char path[1024+4];
  4358.   int init;
  4359. } hts_rootdir_strc;
  4360. HTSEXT_API char* hts_rootdir(char* file) {
  4361.   static hts_rootdir_strc strc = {"", 0};
  4362.   if (file) {
  4363.     if (!strc.init) {
  4364.       strc.path[0]='\0';
  4365.       strc.init=1;
  4366.       if (strnotempty(file)) {
  4367.         char* a;
  4368.         strcpybuff(strc.path,file);
  4369.         while((a=strrchr(strc.path,'\\'))) *a='/';
  4370.         if ((a=strrchr(strc.path,'/'))) {
  4371.           *(a+1)='\0';
  4372.         } else
  4373.           strc.path[0]='\0';
  4374.       }
  4375.       if (!strnotempty(strc.path)) {
  4376.         if( getcwd( strc.path, 1024 ) == NULL )
  4377.             strc.path[0]='\0';
  4378.         else
  4379.           strcatbuff(strc.path,"/");
  4380.       }
  4381.     }
  4382.     return NULL;
  4383.   } else if (strc.init)
  4384.     return strc.path;
  4385.   else
  4386.     return "";
  4387. }
  4388.  
  4389.  
  4390.  
  4391. HTSEXT_API hts_stat_struct HTS_STAT;
  4392. //
  4393. // return  number of downloadable bytes, depending on rate limiter
  4394. // see engine_stats() routine, too
  4395. // this routine works quite well for big files and regular ones, but apparently the rate limiter has
  4396. // some problems with very small files (rate too high)
  4397. LLint check_downloadable_bytes(int rate) {
  4398.   if (rate>0) {
  4399.     TStamp time_now;
  4400.     TStamp elapsed_useconds;
  4401.     LLint bytes_transfered_during_period;
  4402.     LLint left;
  4403.  
  4404.     // get the older timer
  4405.     int id_timer = (HTS_STAT.istat_idlasttimer + 1) % 2;
  4406.  
  4407.     time_now=mtime_local();
  4408.     elapsed_useconds = time_now - HTS_STAT.istat_timestart[id_timer];
  4409.     // NO totally stupid - elapsed_useconds+=1000;      // for the next second, too
  4410.     bytes_transfered_during_period = (HTS_STAT.HTS_TOTAL_RECV-HTS_STAT.istat_bytes[id_timer]);
  4411.     
  4412.     left = ((rate * elapsed_useconds)/1000) - bytes_transfered_during_period;
  4413.     if (left <= 0)
  4414.       left = 0;
  4415.     
  4416.     return left;
  4417.   } else
  4418.     return TAILLE_BUFFER;
  4419. }
  4420.  
  4421. //
  4422. // 0 : OK
  4423. // 1 : slow down
  4424. #if 0
  4425. int HTS_TOTAL_RECV_CHECK(int var) {
  4426.   if (HTS_STAT.HTS_TOTAL_RECV_STATE)
  4427.     return 1;
  4428.     /*
  4429.     {
  4430.     if (HTS_STAT.HTS_TOTAL_RECV_STATE==3) { 
  4431.       var = min(var,32); 
  4432.       Sleep(250); 
  4433.     } else if (HTS_STAT.HTS_TOTAL_RECV_STATE==2) { 
  4434.       var = min(var,256); 
  4435.       Sleep(100); 
  4436.     } else { 
  4437.       var/=2; 
  4438.       if (var<=0) var=1; 
  4439.       Sleep(50); 
  4440.     } 
  4441.   }
  4442.     */
  4443.   return 0;
  4444. }
  4445. #endif
  4446.  
  4447. // Lecture dans buff de size octets au maximum en utilisant la socket r (structure htsblk)
  4448. // returns: 
  4449. // >0 : data received
  4450. // == 0 : not yet data
  4451. // <0: error or no data: READ_ERROR, READ_EOF or READ_TIMEOUT
  4452. HTS_INLINE int hts_read(htsblk* r,char* buff,int size) {
  4453.   int retour;
  4454.   //  return read(soc,buff,size);
  4455.   if (r->is_file) {
  4456. #if HTS_WIDE_DEBUG    
  4457.     DEBUG_W("read(%p, %d, %d)\n" _ (void*) buff _ (int) size _ (int) r->fp);
  4458. #endif
  4459.     if (r->fp)
  4460.       retour = (int)fread(buff,1,size,r->fp);
  4461.     else
  4462.       retour = READ_ERROR;
  4463.   } else {
  4464. #if HTS_WIDE_DEBUG    
  4465.     DEBUG_W("recv(%d, %p, %d)\n" _ (int) r->soc _ (void*) buff _ (int) size);
  4466.     if (r->soc==INVALID_SOCKET)
  4467.       printf("!!WIDE_DEBUG ERROR, soc==INVALID hts_read\n");
  4468. #endif
  4469.     //HTS_TOTAL_RECV_CHECK(size);         // Diminuer au besoin si trop de donnΘes reτues
  4470. #if HTS_USEOPENSSL
  4471.     if (SSL_is_available && r->ssl) {
  4472.       retour = SSL_read(r->ssl_con, buff, size);
  4473.       if (retour <= 0) {
  4474.         int err_code = SSL_get_error(r->ssl_con, retour);
  4475.         if (
  4476.           (err_code == SSL_ERROR_WANT_READ)
  4477.           ||
  4478.           (err_code == SSL_ERROR_WANT_WRITE)
  4479.           ) 
  4480.         {
  4481.           retour = 0;             /* no data yet (ssl cache) */
  4482.         } else if (err_code == SSL_ERROR_ZERO_RETURN) {
  4483.           retour = READ_EOF;             /* completed */
  4484.         } else {
  4485.           retour = READ_ERROR;            /* eof or error */
  4486.         }
  4487.       }
  4488.     } else {
  4489. #endif
  4490.     retour=recv(r->soc,buff,size,0);
  4491.     if (retour == 0) {
  4492.       retour = READ_EOF;
  4493.     } else if (retour < 0) {
  4494.       retour = READ_ERROR;
  4495.     }
  4496.   }
  4497.   if (retour > 0)    // compter flux entrant
  4498.     HTS_STAT.HTS_TOTAL_RECV+=retour;
  4499. #if HTS_USEOPENSSL
  4500.   }
  4501. #endif
  4502. #if HTS_WIDE_DEBUG    
  4503.   DEBUG_W("recv/read done (%d bytes)\n" _ (int) retour);
  4504. #endif
  4505.   return retour;
  4506. }
  4507.  
  4508.  
  4509. // -- Gestion cache DNS --
  4510. // 'RX98
  4511. #if HTS_DNSCACHE
  4512.  
  4513. // 'capsule' contenant uniquement le cache
  4514. t_dnscache* _hts_cache(httrackp *opt) {
  4515.     if (opt->state.dns_cache == NULL) {
  4516.         opt->state.dns_cache = (t_dnscache*)malloct(sizeof(t_dnscache));
  4517.         memset(opt->state.dns_cache, 0, sizeof(t_dnscache));
  4518.     }
  4519.   return opt->state.dns_cache;
  4520. }
  4521. // free the cache
  4522. static void hts_cache_free_(t_dnscache* cache) {
  4523.   if (cache != NULL) {
  4524.     if (cache->n != NULL) {
  4525.       hts_cache_free_(cache->n);
  4526.     }
  4527.     freet(cache);
  4528.   }
  4529. }
  4530. void hts_cache_free(t_dnscache* cache) {
  4531.     if (cache != NULL && cache->n != NULL) {
  4532.         hts_cache_free_(cache->n);
  4533.         cache->n = NULL;
  4534.     }
  4535. }
  4536.  
  4537. // lock le cache dns pour tout opΘration d'ajout
  4538. // plus prudent quand plusieurs threads peuvent Θcrire dedans..
  4539. // -1: status? 0: libΘrer 1:locker
  4540.  
  4541. /* 
  4542.   Simple lock for cache
  4543. */
  4544. htsmutex dns_lock = HTSMUTEX_INIT;
  4545.  
  4546. // routine pour le cache - retour optionnel α donner α chaque fois
  4547. // NULL: nom non encore testΘ dans le cache
  4548. // si h_length==0 alors le nom n'existe pas dans le dns
  4549. t_hostent* _hts_ghbn(t_dnscache* cache,const char* iadr,t_hostent* retour) {
  4550.   t_hostent* ret = NULL;
  4551.   hts_mutexlock(&dns_lock);
  4552.   for(;;) {
  4553.     if (strcmp(cache->iadr,iadr) == 0) {  // ok trouvΘ
  4554.       if (cache->host_length > 0) {  // entrΘe valide
  4555.         if (retour->h_addr_list[0])
  4556.           memcpy(retour->h_addr_list[0], cache->host_addr, cache->host_length);
  4557.         retour->h_length=cache->host_length;
  4558.       } else if (cache->host_length == 0) {  // en cours
  4559.         ret = NULL;
  4560.         break;
  4561.       } else {                    // erreur dans le dns, dΘja vΘrifiΘ
  4562.         if (retour->h_addr_list[0])
  4563.           retour->h_addr_list[0][0]='\0';
  4564.         retour->h_length=0;  // erreur, n'existe pas
  4565.       }
  4566.       ret = retour;
  4567.       break;
  4568.     } else {    // on a pas encore trouvΘ
  4569.       if (cache->n!=NULL) { // chercher encore
  4570.         cache = cache->n;   // suivant!
  4571.       } else {
  4572.         ret = NULL;
  4573.         break;
  4574.       }
  4575.     }    
  4576.   }
  4577.   hts_mutexrelease(&dns_lock);
  4578.   return ret;
  4579. }
  4580.  
  4581. // tester si iadr a dΘja ΘtΘ testΘ (ou en cours de test)
  4582. // 0 non encore
  4583. // 1 ok
  4584. // 2 non prΘsent
  4585. int hts_dnstest(httrackp *opt, const char* _iadr) {
  4586.   int ret = 0;
  4587.   t_dnscache* cache=_hts_cache(opt);  // adresse du cache 
  4588.     char iadr[HTS_URLMAXSIZE*2];
  4589.  
  4590.   // sauter user:pass@ Θventuel
  4591.   strcpybuff(iadr, jump_identification(_iadr));
  4592.   // couper Θventuel :
  4593.   {
  4594.     char *a;
  4595.     if ( (a = jump_toport(iadr)) )
  4596.       *a='\0';
  4597.   }
  4598.  
  4599. #ifdef _WIN32
  4600.   if (inet_addr(iadr)!=INADDR_NONE)  // numΘrique
  4601. #else
  4602.   if (inet_addr(iadr)!=(in_addr_t) -1 )  // numΘrique
  4603. #endif
  4604.     return 1;
  4605.  
  4606.   hts_mutexlock(&dns_lock);
  4607.   for(;;) {
  4608.     if (strcmp(cache->iadr, iadr)==0) {  // ok trouvΘ
  4609.       ret = 1;
  4610.       break;
  4611.     } else {    // on a pas encore trouvΘ
  4612.       if (cache->n!=NULL) { // chercher encore
  4613.         cache=cache->n;   // suivant!
  4614.       } else {
  4615.         ret = 2;    // non prΘsent        
  4616.         break ;
  4617.       }
  4618.     }    
  4619.   }
  4620.   hts_mutexrelease(&dns_lock);
  4621.   return ret;
  4622. }
  4623.  
  4624.  
  4625. HTSEXT_API t_hostent* vxgethostbyname(char* hostname, void* v_buffer) {
  4626.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  4627.   /* Clear */
  4628.   fullhostent_init(buffer);
  4629.  
  4630.   /* Protection */
  4631.   if (!strnotempty(hostname)) {
  4632.     return NULL;
  4633.   }
  4634.  
  4635.   /* 
  4636.     Strip [] if any : [3ffe:b80:1234:1::1] 
  4637.     The resolver doesn't seem to handle IP6 addresses in brackets
  4638.   */
  4639.   if ((hostname[0] == '[') && (hostname[strlen(hostname)-1] == ']')) {
  4640.     char BIGSTK tempo[HTS_URLMAXSIZE*2];
  4641.     tempo[0]='\0';
  4642.     strncatbuff(tempo, hostname+1, strlen(hostname)-2);
  4643.     strcpybuff(hostname, tempo);
  4644.   }
  4645.  
  4646.   {
  4647. #if HTS_INET6==0
  4648.   /*
  4649.   ipV4 resolver
  4650.     */
  4651.     t_hostent* hp=gethostbyname(hostname);
  4652.     if (hp!=NULL) {
  4653.       if ( (hp->h_length) && ( ((unsigned int) hp->h_length) <= buffer->addr_maxlen) ) {
  4654.         memcpy(buffer->hp.h_addr_list[0], hp->h_addr_list[0], hp->h_length);
  4655.         buffer->hp.h_length = hp->h_length;
  4656.         return &(buffer->hp);
  4657.       }
  4658.     }
  4659. #else
  4660.     /*
  4661.     ipV6 resolver
  4662.     */
  4663.     /*
  4664.     int error_num=0;
  4665.     t_hostent* hp=getipnodebyname(hostname, AF_INET6, AI_DEFAULT, &error_num);
  4666.     oops, deprecated :(
  4667.     */
  4668.     struct addrinfo* res = NULL;
  4669.     struct addrinfo hints;
  4670.     memset(&hints, 0, sizeof(hints));
  4671.     if (IPV6_resolver == 1)        // V4 only (for bogus V6 entries)
  4672.       hints.ai_family = PF_INET;
  4673.     else if (IPV6_resolver == 2)   // V6 only (for testing V6 only)
  4674.       hints.ai_family = PF_INET6;
  4675.     else                           // V4 + V6
  4676.       hints.ai_family = PF_UNSPEC;
  4677.     hints.ai_socktype = SOCK_STREAM;
  4678.     hints.ai_protocol = IPPROTO_TCP;
  4679.     if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
  4680.       if (res) {
  4681.         if ( (res->ai_addr) && (res->ai_addrlen) && (res->ai_addrlen <= buffer->addr_maxlen) ) {
  4682.           memcpy(buffer->hp.h_addr_list[0], res->ai_addr, res->ai_addrlen);
  4683.           buffer->hp.h_length = (short) res->ai_addrlen;
  4684.           freeaddrinfo(res);
  4685.           return &(buffer->hp);
  4686.         }
  4687.       }
  4688.     }
  4689.     if (res) {
  4690.       freeaddrinfo(res);
  4691.     }
  4692.     
  4693. #endif
  4694.   }
  4695.   return NULL;
  4696. }
  4697.  
  4698. // cache dns interne α HTS // ** FREE A FAIRE sur la chaine
  4699. t_hostent* hts_gethostbyname(httrackp *opt,const char* _iadr, void* v_buffer) {
  4700.   char BIGSTK iadr[HTS_URLMAXSIZE*2];
  4701.   t_fullhostent* buffer = (t_fullhostent*) v_buffer;
  4702.   t_dnscache* cache=_hts_cache(opt);  // adresse du cache
  4703.   t_hostent* hp;
  4704.  
  4705.   /* Clear */
  4706.   fullhostent_init(buffer);
  4707.  
  4708.   strcpybuff(iadr,jump_identification(_iadr));
  4709.   // couper Θventuel :
  4710.   {
  4711.     char *a;
  4712.     if ( (a=jump_toport(iadr)) )
  4713.       *a='\0';
  4714.   }
  4715.  
  4716.   // effacer structure de retour, crΘer nouvelle
  4717.   /*
  4718.   memset(&host, 0, sizeof(t_hostent));  
  4719.   host.h_addr_list=he;
  4720.   he[0]=NULL;
  4721.   he[1]=NULL;  
  4722.   host.h_length=0;  
  4723.   */
  4724.   cache->iadr[0]='*';
  4725.   cache->iadr[1]='\0';
  4726.   
  4727.   /* get IP from the dns cache */
  4728.   hp = _hts_ghbn(cache, iadr, &buffer->hp);
  4729.   if (hp) {
  4730.     if (hp->h_length>0)
  4731.       return hp;
  4732.     else
  4733.       return NULL;    // entrΘe erronΘe (erreur DNS) dans le DNS
  4734.   } else {  // non prΘsent dans le cache dns, tester
  4735.     t_dnscache* c=cache;
  4736.     while(c->n) c=c->n;    // calculer queue
  4737.     
  4738. #if HTS_WIDE_DEBUG    
  4739.     DEBUG_W("gethostbyname\n");
  4740. #endif      
  4741. #if HDEBUG
  4742.     printf("gethostbyname (not in cache)\n");
  4743. #endif
  4744.     {
  4745.       unsigned long inetaddr;
  4746. #ifdef _WIN32
  4747.       if ((inetaddr=inet_addr(iadr))==INADDR_NONE) {
  4748. #else
  4749.       if ((inetaddr=inet_addr(iadr))==(in_addr_t) -1 ) {
  4750. #endif        
  4751. #if DEBUGDNS 
  4752.         printf("resolving (not cached) %s\n",iadr);
  4753. #endif
  4754.         hp=vxgethostbyname(iadr, buffer);  // calculer IP host
  4755.       } else {     // numΘrique, convertir sans passer par le dns
  4756.         buffer->hp.h_addr_list[0]=(char*) &inetaddr;
  4757.         buffer->hp.h_length=4;
  4758.         hp=&buffer->hp;
  4759.       }
  4760.     }
  4761. #if HTS_WIDE_DEBUG    
  4762.     DEBUG_W("gethostbyname done\n");
  4763. #endif
  4764.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  4765.     if (cache->n!=NULL) {
  4766.       strcpybuff(cache->n->iadr,iadr);
  4767.       if (hp!=NULL) {
  4768.         memcpy(cache->n->host_addr, hp->h_addr_list[0], hp->h_length);
  4769.         cache->n->host_length=hp->h_length;
  4770.       } else {
  4771.         cache->n->host_addr[0]='\0';
  4772.         cache->n->host_length=0;  // non existant dans le dns
  4773.       }
  4774.       cache->n->n=NULL;
  4775.       return hp;
  4776.     } else {  // on peut pas noter, mais on peut renvoyer le rΘsultat
  4777.       return hp;
  4778.     }        
  4779.   }  // retour hp du cache
  4780. }
  4781.  
  4782. #else
  4783. HTS_INLINE t_hostent* hts_gethostbyname(httrackp *opt,char* iadr, t_fullhostent* buffer) {
  4784.   t_hostent* retour;
  4785. #if HTS_WIDE_DEBUG    
  4786.   DEBUG_W("gethostbyname (2)\n");
  4787. #endif
  4788. #if DEBUGDNS 
  4789.     printf("blocking method gethostbyname() in progress for %s\n",iadr);
  4790. #endif
  4791.   retour=vxgethostbyname(jump_identification(iadr), );
  4792. #if HTS_WIDE_DEBUG    
  4793.   DEBUG_W("gethostbyname (2) done\n");
  4794. #endif
  4795.   return retour;
  4796. }
  4797. #endif
  4798.  
  4799.  
  4800. // --- Tracage des mallocs() ---
  4801. #ifdef HTS_TRACE_MALLOC
  4802. //#define htsLocker(A, N) htsLocker(A, N)
  4803. #define htsLocker(A, N) do {} while(0)
  4804. static mlink trmalloc = {NULL,0,0,NULL};
  4805. static int trmalloc_id=0;
  4806. static htsmutex* mallocMutex = NULL;
  4807. static void hts_meminit(void) {
  4808.   //if (mallocMutex == NULL) {
  4809.   //  mallocMutex = calloc(sizeof(*mallocMutex), 1);
  4810.   //  htsLocker(mallocMutex, -999);
  4811.   //}
  4812. }
  4813. void* hts_malloc(size_t len) {
  4814.   void* adr;
  4815.   hts_meminit();
  4816.   htsLocker(mallocMutex, 1);
  4817.   fassert(len > 0);
  4818.   adr = hts_xmalloc(len, 0);
  4819.   htsLocker(mallocMutex, 0);
  4820.   return adr;
  4821. }
  4822. void* hts_calloc(size_t len,size_t len2) {
  4823.   void* adr;
  4824.   hts_meminit();
  4825.   fassert(len > 0);
  4826.   fassert(len2 > 0);
  4827.   htsLocker(mallocMutex, 1);
  4828.   adr = hts_xmalloc(len, len2);
  4829.   htsLocker(mallocMutex, 0);
  4830.   memset(adr, 0, len * len2);
  4831.   return adr;
  4832. }
  4833. void* hts_strdup(char* str) {
  4834.   size_t size = str ? strlen(str) : 0;
  4835.   char* adr = (char*) hts_malloc(size + 1);
  4836.   fassert(adr != NULL);
  4837.   strcpy(adr, str ? str : "");
  4838.   return adr;
  4839. }
  4840. void* hts_xmalloc(size_t len,size_t len2) {
  4841.   mlink* lnk = (mlink*) calloc(1,sizeof(mlink));
  4842.   fassert(lnk != NULL);
  4843.   fassert(len > 0);
  4844.   fassert(len2 >= 0);
  4845.   if (lnk) {
  4846.     void*  r   = NULL;
  4847.     int size, bsize = sizeof(t_htsboundary);
  4848.     if (len2)
  4849.       size = len * len2;
  4850.     else
  4851.       size = len;
  4852.     size += ((bsize - (size % bsize)) % bsize);  /* check alignement */
  4853.     r = malloc(size + bsize*2);
  4854.     fassert(r != NULL);
  4855.     if (r) {
  4856.       * ( (t_htsboundary*) ((char*) r ) ) 
  4857.         = * ( (t_htsboundary*) ( (char*) r + size + bsize ) )
  4858.         = htsboundary;
  4859.       ((char*) r) += bsize;    /* boundary */
  4860.       lnk->adr = r;
  4861.       lnk->len = size;
  4862.       lnk->id = trmalloc_id++;
  4863.       lnk->next = trmalloc.next;
  4864.       trmalloc.next = lnk;
  4865.       return r;
  4866.     } else {
  4867.       free(lnk);
  4868.     }
  4869.   }
  4870.   return NULL;
  4871. }
  4872. void hts_free(void* adr) {
  4873.   mlink* lnk = &trmalloc;
  4874.   int bsize = sizeof(t_htsboundary);
  4875.   fassert(adr != NULL);
  4876.   if (!adr) {
  4877.     return;
  4878.   }
  4879.   htsLocker(mallocMutex, 1);
  4880.   while(lnk->next != NULL) {
  4881.     if (lnk->next->adr == adr) {
  4882.       mlink* blk_free=lnk->next;
  4883.       fassert(blk_free->id != -1);
  4884.       fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary );
  4885.       fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary );
  4886.       lnk->next=lnk->next->next;
  4887.       free((void*) blk_free);
  4888.       //blk_free->id=-1;
  4889.       free((char*) adr - bsize);
  4890.       htsLocker(mallocMutex, 0);
  4891.       return;
  4892.     }
  4893.     lnk = lnk->next;
  4894.     fassert(lnk->next != NULL);
  4895.   }
  4896.   free(adr);
  4897.   htsLocker(mallocMutex, 0);
  4898. }
  4899. void* hts_realloc(void* adr,size_t len) {
  4900.   int bsize = sizeof(t_htsboundary);
  4901.   len += ((bsize - (len % bsize)) % bsize);  /* check alignement */
  4902.   if (adr != NULL) {
  4903.     mlink* lnk = &trmalloc;
  4904.     htsLocker(mallocMutex, 1);
  4905.     while(lnk->next != NULL)  {
  4906.       if (lnk->next->adr==adr) {
  4907.         {
  4908.           mlink* blk_free=lnk->next;
  4909.           fassert(blk_free->id != -1);
  4910.           fassert( * ( (t_htsboundary*) ( (char*) adr - bsize ) ) == htsboundary );
  4911.           fassert( * ( (t_htsboundary*) ( (char*) adr + blk_free->len ) ) == htsboundary );
  4912.         }
  4913.         adr = realloc((char*) adr - bsize, len + bsize * 2);
  4914.         fassert(adr != NULL);
  4915.         lnk->next->adr = (char*) adr + bsize;
  4916.         lnk->next->len = len;
  4917.         * ( (t_htsboundary*) ( (char*) adr ) ) 
  4918.           = * ( (t_htsboundary*) ( (char*) adr + len + bsize) ) 
  4919.           = htsboundary;
  4920.         htsLocker(mallocMutex, 0);
  4921.         return (char*) adr + bsize;
  4922.       }
  4923.       lnk = lnk->next;
  4924.       fassert(lnk->next != NULL);
  4925.     }
  4926.     htsLocker(mallocMutex, 0);
  4927.   }
  4928.   return hts_malloc(len);
  4929. }
  4930. mlink* hts_find(char* adr) {
  4931.   char* stkframe = (char*) &stkframe;
  4932.   mlink* lnk = &trmalloc;
  4933.   int bsize = sizeof(t_htsboundary);
  4934.   fassert(adr != NULL);
  4935.   if (!adr) {
  4936.     return NULL;
  4937.   }
  4938.   htsLocker(mallocMutex, 1);
  4939.   while(lnk->next != NULL) {
  4940.     if (adr >= lnk->next->adr && adr <= lnk->next->adr + lnk->next->len) {   /* found */
  4941.       htsLocker(mallocMutex, 0);
  4942.       return lnk->next;
  4943.     }
  4944.     lnk = lnk->next;
  4945.   }
  4946.   htsLocker(mallocMutex, 0);
  4947.   {
  4948.     int depl = (int) (adr - stkframe);
  4949.     if (depl < 0) depl = -depl;
  4950.     //fassert(depl < 512000);   /* near the stack frame.. doesn't look like malloc but stack variable */
  4951.     return NULL;
  4952.   }
  4953. }
  4954. // check the malloct() and calloct() trace stack
  4955. void  hts_freeall(void) {
  4956.   int bsize = sizeof(t_htsboundary);
  4957.   while(trmalloc.next) {
  4958. #if MEMDEBUG
  4959.     printf("* block %d\t not released: at %d\t (%d\t bytes)\n",trmalloc.next->id,trmalloc.next->adr,trmalloc.next->len);
  4960. #endif
  4961.     if (trmalloc.next->id != -1) {
  4962.       free((char*) trmalloc.next->adr - bsize);
  4963.     }
  4964.   }
  4965. }
  4966. #endif
  4967.  
  4968.  
  4969. // -- divers //
  4970.  
  4971. // cut path and project name
  4972. // patch also initial path
  4973. void cut_path(char* fullpath,char* path,char* pname) {
  4974.   path[0]=pname[0]='\0';
  4975.   if (strnotempty(fullpath)) {
  4976.     if ((fullpath[strlen(fullpath)-1]=='/') || (fullpath[strlen(fullpath)-1]=='\\'))
  4977.       fullpath[strlen(fullpath)-1]='\0';
  4978.     if (strlen(fullpath)>1) {
  4979.       char* a;
  4980.       while( (a=strchr(fullpath,'\\')) ) *a='/';     // remplacer par /
  4981.       a=fullpath+strlen(fullpath)-2;
  4982.       while( (*a!='/') && ( a > fullpath)) a--;
  4983.       if (*a=='/') a++;
  4984.       strcpybuff(pname,a);
  4985.       strncatbuff(path,fullpath,(int) (a - fullpath));
  4986.     }
  4987.   }
  4988. }
  4989.  
  4990.  
  4991.  
  4992. // -- Gestion protocole ftp --
  4993.  
  4994. #ifdef _WIN32
  4995. int ftp_available(void) {
  4996.   return 1;
  4997. }
  4998. #else
  4999. int ftp_available(void) {
  5000.   return 1;   // ok!
  5001.   //return 0;   // SOUS UNIX, PROBLEMESs
  5002. }
  5003. #endif
  5004.  
  5005.  
  5006. int hts_dgb_init = 0;
  5007. FILE* hts_dgb_init_fp = NULL;
  5008. HTSEXT_API void hts_debug(int level) {
  5009.   hts_dgb_init = level;
  5010.   if (hts_dgb_init > 0) {
  5011.     HTS_DBG("hts_debug() called");
  5012.   }
  5013. }
  5014.  
  5015. FILE *hts_dgb_(void) {
  5016.   if (hts_dgb_init_fp == NULL) {
  5017.     if ((hts_dgb_init & 0x80) == 0) {
  5018.       hts_dgb_init_fp = stderr;
  5019.     } else {
  5020. #ifdef _WIN32_WCE
  5021.       hts_dgb_init_fp = fopen("\\Temp\\hts-debug.txt", "wb");
  5022. #else
  5023.       hts_dgb_init_fp = fopen("hts-debug.txt", "wb");
  5024. #endif
  5025.       if (hts_dgb_init_fp != NULL) {
  5026.         fprintf(hts_dgb_init_fp, "* Creating file\r\n");
  5027.       }
  5028.     }
  5029.   }
  5030.   return hts_dgb_init_fp;
  5031. }
  5032.  
  5033. static int hts_init_ok = 0;
  5034. HTSEXT_API int hts_init(void) {
  5035.   const char *dbg_env;
  5036.   /* */
  5037.   if (hts_init_ok)
  5038.     return 1;
  5039.   hts_init_ok = 1;
  5040.  
  5041.   /* enable debugging ? */
  5042.   dbg_env = getenv("HTS_LOG");
  5043.   if (dbg_env != NULL && *dbg_env != 0) {
  5044.     int level = 0;
  5045.     if (sscanf(dbg_env, "%d", &level) == 1) {
  5046.       hts_debug(level);
  5047.     }
  5048.   }
  5049.  
  5050.   HTS_DBG("entering hts_init()");    /* debug */
  5051.  
  5052. #ifdef _WIN32_WCE
  5053. #ifndef HTS_CECOMPAT
  5054.   xceinit(L"");
  5055. #endif
  5056. #endif
  5057.  
  5058.   /* Init threads (lazy init) */
  5059.   htsthread_init();
  5060.  
  5061.   /* Ensure external modules are loaded */
  5062.   HTS_DBG("calling htspe_init()");    /* debug */
  5063.   htspe_init();  /* module load (lazy) */
  5064.  
  5065.   /* MD5 Auto-test */
  5066.   {
  5067.     char digest[32 + 2];
  5068.     const unsigned char* atest = (const unsigned char*)"MD5 Checksum Autotest";
  5069.     digest[0] = '\0';
  5070.     domd5mem(atest, strlen(atest), digest, 1); /* a42ec44369da07ace5ec1d660ba4a69a */
  5071.     if (strcmp(digest, "a42ec44369da07ace5ec1d660ba4a69a") != 0) {
  5072.       int fatal_broken_md5 = 0;
  5073.       assertf(fatal_broken_md5);
  5074.     }
  5075.   }
  5076.  
  5077.   HTS_DBG("initializing SSL");    /* debug */
  5078. #if HTS_USEOPENSSL
  5079.   /*
  5080.   Initialize the OpensSSL library
  5081.   */
  5082.   if (!openssl_ctx && SSL_is_available) {
  5083.     if (SSL_load_error_strings) SSL_load_error_strings();
  5084.     SSL_library_init();
  5085.     ///if (SSL_load_error_strings)  SSL_load_error_strings();
  5086.     //if (ERR_load_crypto_strings) ERR_load_crypto_strings();
  5087.     // if (ERR_load_SSL_strings)    ERR_load_SSL_strings(); ???!!!
  5088.     // OpenSSL_add_all_algorithms();
  5089.     openssl_ctx = SSL_CTX_new(SSLv23_client_method());
  5090.     if (!openssl_ctx) {
  5091.       fprintf(stderr, "fatal: unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)\n");
  5092.       abortLog("unable to initialize TLS: SSL_CTX_new(SSLv23_client_method)");
  5093.       assertf("unable to initialize TLS" == NULL);
  5094.     }
  5095.   }
  5096. #endif
  5097.   
  5098.   HTS_DBG("ending hts_init()");    /* debug */
  5099.   return 1;
  5100. }
  5101.  
  5102. /* will not free thread env. */
  5103. HTSEXT_API int hts_uninit(void) {
  5104.   /* hts_init() is a lazy initializer, with limited a allocation (one or two mutexes) ;
  5105.   we won't free anything here as the .h semantic was never being very clear */
  5106.   return 1;
  5107. }
  5108.  
  5109. HTSEXT_API int hts_uninit_module(void) {
  5110.   if (!hts_init_ok)
  5111.     return 1;
  5112.   htsthread_uninit();
  5113.   htspe_uninit();
  5114.   hts_init_ok = 0;
  5115.   return 1;
  5116. }
  5117.  
  5118. HTSEXT_API int hts_log(httrackp *opt, const char* prefix, const char *msg) {
  5119.   if (opt->log != NULL) {
  5120.     fspc(opt, opt->log, prefix);
  5121.     fprintf(opt->log, "%s"LF, msg);
  5122.     return 0;
  5123.   }
  5124.   return 1;   /* Error */
  5125. }
  5126.  
  5127. HTSEXT_API void set_wrappers(httrackp *opt) {        // LEGACY
  5128. }
  5129.  
  5130. HTSEXT_API int plug_wrapper(httrackp *opt, const char *moduleName, const char* argv) {
  5131.   void* handle = openFunctionLib(moduleName);
  5132.   if (handle != NULL) {
  5133.     t_hts_plug plug = (t_hts_plug) getFunctionPtr(handle, "hts_plug");
  5134.     t_hts_unplug unplug = (t_hts_unplug) getFunctionPtr(handle, "hts_unplug");
  5135.     if (plug != NULL) {
  5136.       int ret = plug(opt, argv);
  5137.       if (hts_dgb_init > 0 && opt->log != NULL) {
  5138.         HTS_DBG("plugged module '%s' (return code=%d)" _ moduleName _ ret);
  5139.       }
  5140.       if (ret == 1) {   /* Success! */
  5141.         opt->libHandles.handles = (htslibhandle*) realloct(opt->libHandles.handles, ( opt->libHandles.count + 1 )*sizeof(htslibhandle));
  5142.         opt->libHandles.handles[opt->libHandles.count].handle = handle;
  5143.         opt->libHandles.handles[opt->libHandles.count].moduleName = strdupt(moduleName);
  5144.         opt->libHandles.count++;
  5145.         return 1;
  5146.       } else {
  5147.         HTS_DBG("* note: error while running entry point 'hts_plug' in %s"LF _ moduleName);
  5148.         if (unplug)
  5149.           unplug(opt);
  5150.       }
  5151.     } else {
  5152.       int last_errno = errno;
  5153.       HTS_DBG("* note: can't find entry point 'hts_plug' in %s: %s"LF _ moduleName _ strerror(last_errno));
  5154.     }
  5155.     closeFunctionLib(handle);
  5156.     return 0;
  5157.   } else {
  5158.     int last_errno = errno;
  5159.     HTS_DBG("* note: can't load %s: %s"LF _ moduleName _ strerror(last_errno));
  5160.   }
  5161.   return -1;
  5162. }
  5163.  
  5164. static void unplug_wrappers(httrackp *opt) {
  5165.   if (opt->libHandles.handles != NULL) {
  5166.     int i;
  5167.     for(i = 0 ; i < opt->libHandles.count ; i++) {
  5168.       if (opt->libHandles.handles[i].handle != NULL) {
  5169.         /* hts_unplug(), the dll exit point (finalizer) */
  5170.         t_hts_unplug unplug = (t_hts_unplug) getFunctionPtr(opt->libHandles.handles[i].handle, "hts_unplug");
  5171.         if (unplug != NULL)
  5172.           unplug(opt);
  5173.         closeFunctionLib(opt->libHandles.handles[i].handle);
  5174.         opt->libHandles.handles[i].handle = NULL;
  5175.       }
  5176.       if (opt->libHandles.handles[i].moduleName != NULL) {
  5177.         freet(opt->libHandles.handles[i].moduleName);
  5178.         opt->libHandles.handles[i].moduleName = NULL;
  5179.       }
  5180.     }
  5181.     freet(opt->libHandles.handles);
  5182.     opt->libHandles.handles = NULL;
  5183.     opt->libHandles.count = 0;
  5184.   }
  5185. }
  5186.  
  5187. int multipleStringMatch(const char *s, const char *match) {
  5188.   int ret = 0;
  5189.   String name = STRING_EMPTY;
  5190.   if (match  == NULL || s == NULL || *s == 0)
  5191.     return 0;
  5192.   for( ; *match != 0 ; match++) {
  5193.     StringClear(name);
  5194.     for( ; *match != 0 && *match != '\n' ; match++) {
  5195.       StringAddchar(name, *match);
  5196.     }
  5197.     if (StringLength(name) > 0 && strstr(s, StringBuff(name)) != NULL) {
  5198.       ret = 1;
  5199.       break ;
  5200.     }
  5201.   }
  5202.   StringFree(name);
  5203.   return ret;
  5204. }
  5205.  
  5206. HTSEXT_API httrackp *hts_create_opt(void) {
  5207. #ifdef _WIN32
  5208.   static const char *defaultModules[] = { 
  5209.     "htsswf", "htsjava", "httrack-plugin", NULL 
  5210.   };
  5211. #else
  5212.   static const char *defaultModules[] = { 
  5213.     "libhtsswf.so.1", "libhtsjava.so.2", "httrack-plugin", NULL 
  5214.   };
  5215. #endif
  5216.   httrackp *opt = malloc(sizeof(httrackp));
  5217.  
  5218.   /* default options */
  5219.   memset(opt, 0, sizeof(httrackp));
  5220.   opt->size_httrackp = sizeof(httrackp);
  5221.  
  5222.   /* mutexes */
  5223.   hts_mutexinit(&opt->state.lock);
  5224.  
  5225.     /* custom wrappers */
  5226.   opt->libHandles.count = 0;
  5227.  
  5228.     /* default settings */
  5229.  
  5230.     opt->wizard=2;   // wizard automatique
  5231.   opt->quiet=0;     // questions
  5232.   //  
  5233.   opt->travel=0;   // mΩme adresse
  5234.   opt->depth=9999; // mirror total par dΘfaut
  5235.   opt->extdepth=0; // mais pas α l'extΘrieur
  5236.   opt->seeker=1;   // down 
  5237.   opt->urlmode=2;  // relatif par dΘfaut
  5238.   opt->debug=0;    // pas de dΘbug en plus
  5239.   opt->getmode=3;  // linear scan
  5240.   opt->maxsite=-1; // taille max site (aucune)
  5241.   opt->maxfile_nonhtml=-1; // taille max fichier non html
  5242.   opt->maxfile_html=-1;    // idem pour html
  5243.   opt->maxsoc=4;     // nbre socket max
  5244.   opt->fragment=-1;  // pas de fragmentation
  5245.   opt->nearlink=0;   // ne pas prendre les liens non-html "adjacents"
  5246.   opt->makeindex=1;  // faire un index
  5247.   opt->kindex=0;     // index 'keyword'
  5248.   opt->delete_old=1; // effacer anciens fichiers
  5249.   opt->makestat=0;  // pas de fichier de stats
  5250.   opt->maketrack=0; // ni de tracking
  5251.   opt->timeout=120; // timeout par dΘfaut (2 minutes)
  5252.   opt->cache=1;     // cache prioritaire
  5253.   opt->shell=0;     // pas de shell par defaut
  5254.   opt->proxy.active=0;    // pas de proxy
  5255.   opt->user_agent_send=1; // envoyer un user-agent
  5256.   StringCopy(opt->user_agent, "Mozilla/4.5 (compatible; HTTrack 3.0x; Windows 98)");
  5257.   StringCopy(opt->referer, "");
  5258.   StringCopy(opt->from, "");
  5259.   opt->savename_83=0;     // noms longs par dΘfaut
  5260.   opt->savename_type=0;   // avec structure originale
  5261.   opt->savename_delayed=2;// hard delayed type (default)
  5262.   opt->delayed_cached=1;  // cached delayed type (default)
  5263.   opt->mimehtml=0;        // pas MIME-html
  5264.   opt->parsejava=HTSPARSE_DEFAULT; // parser classes
  5265.   opt->hostcontrol=0;     // PAS de control host pour timeout et traffic jammer
  5266.   opt->retry=2;           // 2 retry par dΘfaut
  5267.   opt->errpage=1;         // copier ou gΘnΘrer une page d'erreur en cas d'erreur (404 etc.)
  5268.   opt->check_type=1;      // vΘrifier type si inconnu (cgi,asp..) SAUF / considΘrΘ comme html
  5269.   opt->all_in_cache=0;    // ne pas tout stocker en cache
  5270.   opt->robots=2;          // traiter les robots.txt
  5271.   opt->external=0;        // liens externes normaux
  5272.   opt->passprivacy=0;     // mots de passe dans les fichiers
  5273.   opt->includequery=1;    // include query-string par dΘfaut
  5274.   opt->mirror_first_page=0;  // pas mode mirror links
  5275.   opt->accept_cookie=1;   // gΘrer les cookies
  5276.   opt->cookie=NULL;
  5277.   opt->http10=0;          // laisser http/1.1
  5278.   opt->nokeepalive = 0;   // pas keep-alive
  5279.   opt->nocompression=0;   // pas de compression
  5280.   opt->tolerant=0;        // ne pas accepter content-length incorrect
  5281.   opt->parseall=1;        // tout parser (tags inconnus, par exemple)
  5282.   opt->parsedebug=0;      // pas de mode dΘbuggage
  5283.   opt->norecatch=0;       // ne pas reprendre les fichiers effacΘs par l'utilisateur
  5284.   opt->verbosedisplay=0;  // pas d'animation texte
  5285.   opt->sizehack=0;        // size hack
  5286.   opt->urlhack=1;         // url hack (normalizer)
  5287.   StringCopy(opt->footer,HTS_DEFAULT_FOOTER);
  5288.   opt->ftp_proxy=1;       // proxy http pour ftp
  5289.   StringCopy(opt->filelist,"");
  5290.   StringCopy(opt->lang_iso,"en, *");
  5291.   StringCopy(opt->mimedefs,"\n"); // aucun filtre mime (\n IMPORTANT)
  5292.   StringClear(opt->mod_blacklist);
  5293.   //
  5294.   opt->log = stdout;
  5295.   opt->errlog = stderr;
  5296.   opt->flush = 1;         // flush sur les fichiers log
  5297.   //opt->aff_progress=0;
  5298.   opt->keyboard=0;
  5299.   //
  5300.   StringCopy(opt->path_html,"");
  5301.   StringCopy(opt->path_log,"");
  5302.   StringCopy(opt->path_bin,"");
  5303.   //
  5304. #if HTS_SPARE_MEMORY==0
  5305.   opt->maxlink=100000;    // 100,000 liens max par dΘfaut (400Kb)
  5306.   opt->maxfilter=200;     // 200 filtres max par dΘfaut
  5307. #else
  5308.   opt->maxlink=10000;     // 10,000 liens max par dΘfaut (40Kb)
  5309.   opt->maxfilter=50;      // 50 filtres max par dΘfaut
  5310. #endif
  5311.   opt->maxcache=1048576*32;  // a peu prΦs 32Mo en cache max -- OPTION NON PARAMETRABLE POUR L'INSTANT --
  5312.   //opt->maxcache_anticipate=256;  // maximum de liens α anticiper
  5313.   opt->maxtime=-1;        // temps max en secondes
  5314. #if HTS_USEMMS
  5315.     opt->mms_maxtime = 60*3600;        // max time for mms streams (one hour)
  5316. #endif
  5317.   opt->maxrate=25000;     // taux maxi
  5318.   opt->maxconn=5.0;       // nombre connexions/s
  5319.   opt->waittime=-1;       // wait until.. hh*3600+mm*60+ss
  5320.   //
  5321.   opt->exec="";
  5322.   opt->is_update=0;      // not an update (yet)
  5323.   opt->dir_topindex=0;   // do not built top index (yet)
  5324.   //
  5325.   opt->bypass_limits=0;  // enforce limits by default
  5326.   opt->state.stop=0;     // stopper
  5327.   opt->state.exit_xh=0;  // abort
  5328.  
  5329.   /* Alocated buffers */
  5330.  
  5331.     opt->callbacks_fun = (t_hts_htmlcheck_callbacks*) malloct(sizeof(t_hts_htmlcheck_callbacks));
  5332.     memset(opt->callbacks_fun, 0, sizeof(t_hts_htmlcheck_callbacks));
  5333.  
  5334.   /* Preload callbacks : java and flash parser, and the automatic user-defined callback */
  5335.  
  5336.   {
  5337.     int i;
  5338.     for(i = 0 ; defaultModules[i] != NULL ; i++) {
  5339.       int ret = plug_wrapper(opt, defaultModules[i], defaultModules[i]);
  5340.       if (ret == 0) {     /* Module aborted initialization */
  5341.         /* Ignored. */
  5342.       }
  5343.     }
  5344.   }
  5345.  
  5346.     return opt;
  5347. }
  5348.  
  5349. HTSEXT_API void hts_free_opt(httrackp *opt) {
  5350.   if (opt != NULL) {
  5351.  
  5352.     /* Alocated callbacks */
  5353.  
  5354.     if (opt->callbacks_fun != NULL) {
  5355.       int i;
  5356.       t_hts_htmlcheck_callbacks_item *items = (t_hts_htmlcheck_callbacks_item*) opt->callbacks_fun;
  5357.       const int size = (int) sizeof(t_hts_htmlcheck_callbacks) / sizeof(t_hts_htmlcheck_callbacks_item);
  5358.       assertf(sizeof(t_hts_htmlcheck_callbacks_item)*size == sizeof(t_hts_htmlcheck_callbacks));
  5359.  
  5360.       /* Free all linked lists */
  5361.       for(i = 0 ; i < size ; i++) {
  5362.         t_hts_callbackarg *carg, *next_carg;
  5363.         for(carg = items[i].carg ; carg != NULL && (next_carg = carg->prev.carg, carg != NULL) ; carg = next_carg ) {
  5364.           hts_free(carg);
  5365.         }
  5366.       }
  5367.  
  5368.       freet(opt->callbacks_fun);
  5369.       opt->callbacks_fun = NULL;
  5370.     }
  5371.  
  5372.     /* Close library handles */
  5373.     unplug_wrappers(opt);
  5374.  
  5375.     /* Cache */
  5376.     if (opt->state.dns_cache != NULL) {
  5377.       hts_cache_free(opt->state.dns_cache);
  5378.       opt->state.dns_cache = NULL;
  5379.     }
  5380.  
  5381.     /* Cancel chain */
  5382.     if (opt->state.cancel != NULL) {
  5383.       htsoptstatecancel *cancel;
  5384.       for(cancel = opt->state.cancel ; cancel != NULL ; ) {
  5385.         htsoptstatecancel *next = cancel->next;
  5386.         if (cancel->url != NULL) {
  5387.           freet(cancel->url);
  5388.         }
  5389.         freet(cancel);
  5390.         cancel = next;
  5391.       }
  5392.       opt->state.cancel = NULL;
  5393.     }
  5394.  
  5395.     /* Free strings */
  5396.  
  5397.     StringFree(opt->proxy.name);
  5398.     StringFree(opt->proxy.bindhost);
  5399.  
  5400.     StringFree(opt->savename_userdef);
  5401.     StringFree(opt->user_agent);
  5402.     StringFree(opt->referer);
  5403.     StringFree(opt->from);
  5404.     StringFree(opt->lang_iso);
  5405.     StringFree(opt->sys_com);
  5406.     StringFree(opt->mimedefs);
  5407.     StringFree(opt->filelist);
  5408.     StringFree(opt->urllist);
  5409.     StringFree(opt->footer);
  5410.     StringFree(opt->mod_blacklist);
  5411.  
  5412.     StringFree(opt->path_html);
  5413.     StringFree(opt->path_log);
  5414.     StringFree(opt->path_bin);
  5415.  
  5416.     /* mutexes */
  5417.     hts_mutexfree(&opt->state.lock);
  5418.  
  5419.     /* Free structure */
  5420.     free(opt);
  5421.   }
  5422. }
  5423.  
  5424. // defaut wrappers
  5425. static void __cdecl htsdefault_init(t_hts_callbackarg *carg) {
  5426. }
  5427. static void __cdecl htsdefault_uninit(t_hts_callbackarg *carg) {
  5428.   // hts_freevar();
  5429. }
  5430. static int __cdecl htsdefault_start(t_hts_callbackarg *carg, httrackp* opt) {
  5431.   return 1; 
  5432. }
  5433. static int __cdecl htsdefault_chopt(t_hts_callbackarg *carg, httrackp* opt) {
  5434.   return 1;
  5435. }
  5436. static int  __cdecl htsdefault_end(t_hts_callbackarg *carg, httrackp* opt) { 
  5437.   return 1; 
  5438. }
  5439. static int __cdecl htsdefault_preprocesshtml(t_hts_callbackarg *carg, httrackp *opt, char** html,int* len,const char* url_adresse,const char* url_fichier) {
  5440.   return 1;
  5441. }
  5442. static int __cdecl htsdefault_postprocesshtml(t_hts_callbackarg *carg, httrackp *opt, char** html,int* len,const char* url_adresse,const char* url_fichier) {
  5443.   return 1;
  5444. }
  5445. static int __cdecl htsdefault_checkhtml(t_hts_callbackarg *carg, httrackp *opt, char* html,int len,const char* url_adresse,const char* url_fichier) {
  5446.   return 1;
  5447. }
  5448. static int __cdecl htsdefault_loop(t_hts_callbackarg *carg, httrackp *opt, lien_back* back,int back_max,int back_index,int lien_n,int lien_tot,int stat_time,hts_stat_struct* stats) {    // appelΘ α chaque boucle de HTTrack
  5449.   return 1;
  5450. }
  5451. static const char* __cdecl htsdefault_query(t_hts_callbackarg *carg, httrackp *opt, const char* question) {
  5452.   return "";
  5453. }
  5454. static const char* __cdecl htsdefault_query2(t_hts_callbackarg *carg, httrackp *opt, const char* question) {
  5455.   return "";
  5456. }
  5457. static const char* __cdecl htsdefault_query3(t_hts_callbackarg *carg, httrackp *opt, const char* question) {
  5458.   return "";
  5459. }
  5460. static int __cdecl htsdefault_check(t_hts_callbackarg *carg, httrackp *opt, const char* adr,const char* fil,int status) {
  5461.   return -1;
  5462. }
  5463. static int __cdecl htsdefault_check_mime(t_hts_callbackarg *carg, httrackp *opt, const char* adr,const char* fil,const char* mime,int status) {
  5464.   return -1;
  5465. }
  5466. static void __cdecl htsdefault_pause(t_hts_callbackarg *carg, httrackp *opt, const char* lockfile) {
  5467.   while (fexist(lockfile)) {
  5468.     Sleep(1000);
  5469.   }
  5470. }
  5471. static void __cdecl htsdefault_filesave(t_hts_callbackarg *carg, httrackp *opt, const char* file) {
  5472. }
  5473. static void __cdecl htsdefault_filesave2(t_hts_callbackarg *carg, httrackp *opt, const char* adr, const char* file, const char* sav, int is_new, int is_modified, int not_updated) {
  5474. }
  5475. static int __cdecl htsdefault_linkdetected(t_hts_callbackarg *carg, httrackp *opt, char* link) {
  5476.   return 1;
  5477. }
  5478. static int __cdecl htsdefault_linkdetected2(t_hts_callbackarg *carg, httrackp *opt, char* link, const char* start_tag) {
  5479.   return 1;
  5480. }
  5481. static int __cdecl htsdefault_xfrstatus(t_hts_callbackarg *carg, httrackp *opt, lien_back* back) {
  5482.   return 1;
  5483. }
  5484. static int __cdecl htsdefault_savename(t_hts_callbackarg *carg, httrackp *opt, const char* adr_complete,const char* fil_complete,const char* referer_adr,const char* referer_fil,char* save) {
  5485.   return 1;
  5486. }
  5487. static int __cdecl htsdefault_sendhead(t_hts_callbackarg *carg, httrackp *opt, char* buff, const char* adr, const char* fil, const char* referer_adr, const char* referer_fil, htsblk* outgoing) {
  5488.   return 1;
  5489. }
  5490. static int __cdecl htsdefault_receivehead(t_hts_callbackarg *carg, httrackp *opt, char* buff, const char* adr, const char* fil, const char* referer_adr, const char* referer_fil, htsblk* incoming) {
  5491.   return 1;
  5492. }
  5493. static int __cdecl htsdefault_detect(t_hts_callbackarg *carg, httrackp *opt, htsmoduleStruct* str) {
  5494.   return 0;
  5495. }
  5496. static int __cdecl htsdefault_parse(t_hts_callbackarg *carg, httrackp *opt, htsmoduleStruct* str) {
  5497.   return 0;
  5498. }
  5499.  
  5500.  
  5501. /* Default internal dummy callbacks */
  5502. const t_hts_htmlcheck_callbacks default_callbacks = {
  5503.     { htsdefault_init, NULL },
  5504.     { htsdefault_uninit, NULL },
  5505.     { htsdefault_start, NULL },
  5506.     { htsdefault_end, NULL },
  5507.     { htsdefault_chopt, NULL },
  5508.     { htsdefault_preprocesshtml, NULL },
  5509.     { htsdefault_postprocesshtml, NULL },
  5510.     { htsdefault_checkhtml, NULL },
  5511.     { htsdefault_query, NULL },
  5512.     { htsdefault_query2, NULL },
  5513.     { htsdefault_query3, NULL },
  5514.     { htsdefault_loop, NULL },
  5515.     { htsdefault_check, NULL },
  5516.     { htsdefault_check_mime, NULL },
  5517.     { htsdefault_pause, NULL },
  5518.     { htsdefault_filesave, NULL },
  5519.     { htsdefault_filesave2, NULL },
  5520.     { htsdefault_linkdetected, NULL },
  5521.     { htsdefault_linkdetected2, NULL },
  5522.     { htsdefault_xfrstatus, NULL },
  5523.     { htsdefault_savename, NULL },
  5524.     { htsdefault_sendhead, NULL },
  5525.     { htsdefault_receivehead, NULL },
  5526.     { htsdefault_detect, NULL },
  5527.     { htsdefault_parse, NULL }
  5528. };
  5529.  
  5530. #define CHARCAST(A) ( (char*) (A) )
  5531. #define OFFSET_OF(TYPE, MEMBER) ( (size_t) ( CHARCAST(&(((TYPE*) NULL)->MEMBER)) - CHARCAST((TYPE*) NULL) ) )
  5532. #define CALLBACK_REF(name, fun) \
  5533.   { name, OFFSET_OF(t_hts_htmlcheck_callbacks, fun) }
  5534. #define MEMBER_OF(STRUCT, OFFSET, TYPE) ( * ((TYPE*)((char*)(STRUCT) + (OFFSET))) )
  5535.  
  5536. const t_hts_callback_ref default_callbacks_ref[] = {
  5537.     CALLBACK_REF("init", init),
  5538.     CALLBACK_REF("free", uninit),
  5539.     CALLBACK_REF("start", start),
  5540.     CALLBACK_REF("end", end),
  5541.     CALLBACK_REF("change-options", chopt),
  5542.     CALLBACK_REF("preprocess-html", preprocess),
  5543.     CALLBACK_REF("postprocess-html", postprocess),
  5544.     CALLBACK_REF("check-html", check_html),
  5545.     CALLBACK_REF("query", query),
  5546.     CALLBACK_REF("query2", query2),
  5547.     CALLBACK_REF("query3", query3),
  5548.     CALLBACK_REF("loop", loop),
  5549.     CALLBACK_REF("check-link", check_link),
  5550.     CALLBACK_REF("check-mime", check_mime),
  5551.     CALLBACK_REF("pause", pause),
  5552.     CALLBACK_REF("save-file", filesave),
  5553.     CALLBACK_REF("save-file2", filesave2),
  5554.     CALLBACK_REF("link-detected", linkdetected),
  5555.     CALLBACK_REF("link-detected2", linkdetected2),
  5556.     CALLBACK_REF("transfer-status", xfrstatus),
  5557.     CALLBACK_REF("save-name", savename),
  5558.     CALLBACK_REF("send-header", sendhead),
  5559.     CALLBACK_REF("receive-header", receivehead),
  5560.     { NULL, 0 }
  5561. };
  5562.  
  5563. size_t hts_get_callback_offs(const char *name) {
  5564.     const t_hts_callback_ref *ref;
  5565.     for(ref = &default_callbacks_ref[0] ; ref->name != NULL ; ref++) {
  5566.         if (strcmp(name, ref->name) == 0) {
  5567.             return ref->offset;
  5568.         }
  5569.     }
  5570.     return (size_t)(-1);
  5571. }
  5572.  
  5573. int hts_set_callback(t_hts_htmlcheck_callbacks *callbacks, const char *name, void *function) {
  5574.     size_t offs = hts_get_callback_offs(name);
  5575.     if (offs != (size_t) -1) {
  5576.         MEMBER_OF(callbacks, offs, void*) = function;
  5577.         return 0;
  5578.     }
  5579.     return 1;
  5580. }
  5581.  
  5582. void *hts_get_callback(t_hts_htmlcheck_callbacks *callbacks, const char *name) {
  5583.     size_t offs = hts_get_callback_offs(name);
  5584.     if (offs != (size_t) -1) {
  5585.         return MEMBER_OF(callbacks, offs, void*);
  5586.     }
  5587.     return NULL;
  5588. }
  5589.  
  5590. // end defaut wrappers
  5591.  
  5592. /* libc stubs */
  5593.  
  5594. HTSEXT_API char* hts_strdup(const char* str) {
  5595.   return strdup(str);
  5596. }
  5597.  
  5598. HTSEXT_API void* hts_malloc(size_t size) {
  5599.   return malloc(size);
  5600. }
  5601.  
  5602. HTSEXT_API void* hts_realloc(void* data, size_t size) {
  5603.   return realloc(data, size);
  5604. }
  5605.  
  5606. HTSEXT_API void hts_free(void* data) {
  5607.   free(data);
  5608. }
  5609.  
  5610. /* Dummy functions */
  5611. HTSEXT_API int hts_resetvar(void) {
  5612.     return 0;
  5613. }
  5614.  
  5615. #ifdef _WIN32
  5616.  
  5617. typedef struct dirent dirent;
  5618. DIR *opendir(const char *name) {
  5619.   WIN32_FILE_ATTRIBUTE_DATA st;
  5620.   DIR *dir;
  5621.   size_t len;
  5622.   int i;
  5623.   if (name == NULL || *name == '\0') {
  5624.     errno = ENOENT;
  5625.     return NULL;
  5626.   }
  5627.   if (!GetFileAttributesEx(name, GetFileExInfoStandard, &st)
  5628.     || ( st.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) == 0) {
  5629.     errno = ENOENT;
  5630.     return NULL;
  5631.   }
  5632.   dir = calloc(sizeof(DIR), 1);
  5633.   if (dir == NULL) {
  5634.     errno = ENOMEM;
  5635.     return NULL;
  5636.   }
  5637.   len = strlen(name);
  5638.   dir->h = INVALID_HANDLE_VALUE;
  5639.   dir->name = malloc(len + 2 + 1);
  5640.   strcpy(dir->name, name);
  5641.   for(i = 0 ; dir->name[i] != '\0' ; i++) {
  5642.     if (dir->name[i] == '/') {
  5643.       dir->name[i] = '\\';
  5644.     }
  5645.   }
  5646.   strcat(dir->name, "\\*");
  5647.   return dir;
  5648. }
  5649.  
  5650. struct dirent *readdir(DIR *dir) {
  5651.   WIN32_FIND_DATAA find;
  5652.   if (dir->h == INVALID_HANDLE_VALUE) {
  5653.     dir->h = FindFirstFileA(dir->name, &find);
  5654.   } else {
  5655.     if (!FindNextFile(dir->h, &find)) {
  5656.       FindClose(dir->h);
  5657.       dir->h = INVALID_HANDLE_VALUE;
  5658.     }
  5659.   }
  5660.   if (dir->h != INVALID_HANDLE_VALUE) {
  5661.     dir->entry.d_name[0] = 0;
  5662.     strncat(dir->entry.d_name, find.cFileName, HTS_DIRENT_SIZE - 1);
  5663.     return &dir->entry;
  5664.   }
  5665.   errno = ENOENT;
  5666.   return NULL;
  5667. }
  5668.  
  5669. int closedir(DIR *dir) {
  5670.   if (dir != NULL) {
  5671.     if (dir->h != INVALID_HANDLE_VALUE) {
  5672.       CloseHandle(dir->h);
  5673.     }
  5674.     if (dir->name != NULL) {
  5675.       free(dir->name);
  5676.     }
  5677.     free(dir);
  5678.     return 0;
  5679.   }
  5680.   errno = EBADF;
  5681.   return -1;
  5682. }
  5683. #endif
  5684.  
  5685. // Fin
  5686.  
  5687.